투케이2K

148. (TWOK/UTIL) [Ios/Swift] C_FTP_NWConnection_Client_Module : FTP 파일 업로드 및 다운로드 , 사용자 인증 유틸 본문

투케이2K 유틸파일

148. (TWOK/UTIL) [Ios/Swift] C_FTP_NWConnection_Client_Module : FTP 파일 업로드 및 다운로드 , 사용자 인증 유틸

투케이2K 2024. 12. 6. 18:49

[설 명]

프로그램 : Ios / Swift

설 명 : C_FTP_NWConnection_Client_Module : FTP 파일 업로드 및 다운로드 , 사용자 인증 유틸

 

[소스 코드]

 

import Foundation
import UIKit
// -----------------------------------------
//MARK: [네트워크 소켓 통신 사용]
import Network
// -----------------------------------------

class C_FTP_NWConnection_Client_Module {
    
    
    
    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * TODO [클래스 설명]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 1. NWConnection FTP 연결 및 파일 업로드, 다운로드 관련 클래스
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 2. NWConnection : ios 12 이상 부터 사용 가능한 애플에서 지원하는 네트워크 프레임 워크입니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 3. NWConnection 는 로컬 엔드포인트와 원격 엔드포인트 간의 양방향 데이터 연결 (TCP , UDP) 을 수행할 수 있습니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 4. NWConnection 를 사용하기 위해서는 import Network 패키지 호출 정의가 필요합니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 5. NWParameters 설정 가능 옵션 : tls , tcp , dtls , udp , quic , quicDatagram
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 6. 애플 공식 참고 사이트 : https://developer.apple.com/documentation/network/nwconnection
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * */





    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * TODO [빠른 로직 찾기 : 주석 로직 찾기]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableFtpConnect : FTP 연결 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : closeFtpConnect : FTP 연결 종료 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : receiveData : 실시간 메시지 수신 상태 확인
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableUserAuth : FTP 사용자 ID 인증 요청 상태 확인
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observablePwAuth : FTP 사용자 PW 인증 요청 상태 확인
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : loginCallbackReturn : FTP 로그인 콜백 처리 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableUploadFile : 실시간 파일 업로드 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableDownloadFile : 실시간 파일 다운로드 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observablePassiveMode : 파일 다운로드 패시브 모드 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableNewDownloadConnection : 파일 다운로드 NEW 새로운 접속 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : receiveFile : 실시간 파일 다운로드 수신 상태 확인
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : downloadCallbackReturn : FTP 파일 다운로드 콜백 처리 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     *
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     */
    
    
    
    
    
    
    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * TODO [소스 코드 사용 방법]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     DispatchQueue.main.async { // [비동기 요청]
         
         // [FTP 접속을 위한 변수 선언]
         let server = "twok2k.dothome.co.kr"
         let port = 21 // [FTP 는 21 번 포트]
         let userName = "twok2k"
         let pw = "twok00$$admin"
         
         // -----------------------------------------
         // [FTP 연결 요청 수행]
         // -----------------------------------------
         // 1. 사용자 FPT 서버 활성 접속 상태 확인
         // -----------------------------------------
         // 2. USER 커맨드를 사용해 사용자 ID 인증 요청
         // -----------------------------------------
         // 3. PASS 커맨드를 사용해 사용자 PW 인증 요청
         // -----------------------------------------
         C_FTP_NWConnection_Client_Module().observableFtpConnect(server: server, port: UInt16(port), userName: userName, pw: pw){(connectResult) in
             
             S_Log._F_(description: "FTP 연결 확인 수행", data: ["\(connectResult)"])

             if connectResult == true {
                
                 // -----------------------------------------
                 // [FTP 파일 업로드 로직]
                 // -----------------------------------------
                 // 1. STOR 커맨드 사용해 파일 업로드 상태 전환
                 // -----------------------------------------
                 // 2. 앱 내부 로컬에 저장 된 파일 send 보내기 수행
                 // -----------------------------------------
                 /*
                 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // [5초 시간 설정]
                  
                     let fileUrl = C_App().get_File_Url(folderName: "LOG_FILE_FOLDER", fileName: "APP_CRASH_LOG_FILE.txt")
                     
                     S_Log._F_(description: "FTP 파일 송수신 URL 확인", data: ["\(String(describing: fileUrl))"])
                     
                     C_FTP_NWConnection_Client_Module().observableUploadFile(fileUrl: fileUrl?.description ?? "", remoteUrl:"/html/crash.txt"){(sendResult) in
                         
                         S_Log._F_(description: "FTP 실시간 파일 전송 확인", data: ["\(sendResult)"])

                         if sendResult == true {
                            
                         }
                         else {
                            S_Log._F_(description: "FTP 실시간 파일 전송 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)"])
                         }
                         
                     }
                     
                 }
                 // */
                 
                 
                 
                 // -----------------------------------------
                 // [FTP 파일 다운로드 로직]
                 // -----------------------------------------
                 // 1. TYPE 커맨드 사용해 바이너리 업로드 상태 전환
                 // -----------------------------------------
                 // 2. PASV 커맨드 사용해 패시브 모드 상태 전환
                 // -----------------------------------------
                 // 3. 성공적으로 패시브 모드 전환 시 새롭게 내려온 NEW 서버 주소 파싱 수행 : Entering Passive Mode (112,175,185,132,198,97)
                 // -----------------------------------------
                 // 4. NWConnection 새롭게 생성 후 ready 상태로 진입 수행
                 // -----------------------------------------
                 // 5. PASV 커맨드 사용해 로그인 한 커넥션 객체로 send 메시지 전송 (파일 내려 주세요. 요청)
                 // -----------------------------------------
                 // 6. 신규 NWConnection 객체 reciveFile 리시버에서 파일 다운로드가 응답 되면 앱 내부에 파일 저장 수행
                 // -----------------------------------------
                 /*
                 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // [5초 시간 설정]
                     
                     C_FTP_NWConnection_Client_Module().observableDownloadFile(remoteUrl: "/html/crash.txt", localFileName:"crash.txt"){(sendResult) in
                         
                         S_Log._F_(description: "FTP 실시간 파일 다운로드 확인", data: ["\(sendResult)"])

                         if sendResult == true {
                            
                         }
                         else {
                            S_Log._F_(description: "FTP 실시간 파일 다운로드 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"])
                         }
                         
                     }
                     
                 }
                 // */
                 
             }
             else {
                S_Log._F_(description: "FTP 연결 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"])
             }
             
         }
     }
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * */
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [전역 변수 선언]
    // -----------------------------------------------------------------------------------------
    private static let ACTIVITY_NAME = "C_FTP_NWConnection_Client_Module"
    
    let CONNECT_TIME_OUT = 20.0 // [연결 타임 아웃 시간]
    
    lazy var tcpOptions: NWProtocolTCP.Options = {
        let options = NWProtocolTCP.Options()
        options.noDelay = true // [딜레이 비활성]
        options.connectionTimeout = Int(self.CONNECT_TIME_OUT) // [connection timed out]
        return options
    }()

    lazy var parames: NWParameters = {
        let parames = NWParameters(tls: nil, tcp: self.tcpOptions)
        if let isOption = parames.defaultProtocolStack.internetProtocol as? NWProtocolIP.Options {
            //isOption.version = .v4 // [ipv4 방식 : 192.168.1.1]
        }
        parames.preferNoProxies = true
        return parames
    }()
    
    static var connection: NWConnection? = nil // [FTP 통신 수행 객체]
    var workItem: DispatchWorkItem? = nil // [연결 타임 아웃 핸들러]
    
    static var fileNwconnection: NWConnection? = nil // [파일 다운로드 통신 객체]
    
    static var connectFlag = false // MARK: [FTP 연결 및 로그인 수행 완료 플래그 값]
    static var downloadFlag = false // MARK: [FTP 파일 다운로드 완료 플래그 값]
    
    static var FTP_SERTVER = "" // [지속 사용]
    static var FTP_PORT = 0 // [지속 사용]
    static var FTP_USER_NAME = "" // [지속 사용]
    static var FTP_USER_PW = "" // [지속 사용]
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableFtpConnect : FTP 연결 수행
    // -----------------------------------------------------------------------------------------
    // 1. 사용자 FPT 서버 활성 접속 상태 확인
    // -----------------------------------------------------------------------------------------
    // 2. USER 커맨드를 사용해 사용자 ID 인증 요청
    // -----------------------------------------------------------------------------------------
    // 3. PASS 커맨드를 사용해 사용자 PW 인증 요청
    // -----------------------------------------------------------------------------------------
    static var FTP_CONNECT_LOG = ""
    static var connectOperationQueue = OperationQueue()
    func observableFtpConnect(server: String, port: UInt16, userName: String, pw: String, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableFtpConnect 메소드 설명]
        // -----------------------------------------
        1. 도메인, 사용자 정보 사용해 FTP 연결 수행
        // -----------------------------------------
        2. 호출 방법 : MARK: [FTP 포트는 21 번 포트]
         
         C_FTP_NWConnection_Client_Module().observableFtpConnect(server: "towk.test.co.kr", port: UInt16(21), userName: "twok123", pw: "twok0123456789"){(connectResult) in
             
             S_Log._F_(description: "FTP 연결 확인 수행", data: ["\(connectResult)"])

             if connectResult == true {
                
                // [FTP 연결 완료 로직 처리]
             }
             else {
                S_Log._F_(description: "FTP 연결 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */


        // [변수 선언 및 초기화]
        C_FTP_NWConnection_Client_Module.connection = nil
        C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = ""
        self.workItem = nil
        C_FTP_NWConnection_Client_Module.connectFlag = false // MARK: [최종 서버 접속 및 로그인 성공 플래그 처리 변수]
        
        C_FTP_NWConnection_Client_Module.FTP_SERTVER = ""
        C_FTP_NWConnection_Client_Module.FTP_PORT = 0
        C_FTP_NWConnection_Client_Module.FTP_USER_NAME = ""
        C_FTP_NWConnection_Client_Module.FTP_USER_PW = ""
        
        
        // MARK: [작업 큐에 추가]
        C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = true
        let block = { completion(C_FTP_NWConnection_Client_Module.connectFlag) }
        C_FTP_NWConnection_Client_Module.connectOperationQueue.addOperation(block)
        
        
        // [로직 처리 수행]
        DispatchQueue.main.async {
            S_Log._D_(description: "FTP 연결 수행", data: [ "SERVER :: \(server)", "PORT :: \(port)", "USER_NAME :: \(userName)", "PW :: \(pw)" ])
            
            
            // [인풋 데이터 널 체크]
            if C_Util().stringNotNull(str: server) == true && port >= 0
                && C_Util().stringNotNull(str: userName) == true && C_Util().stringNotNull(str: pw) == true {
                
                // ---------------------------------------------
                // MARK: [전역 변수 지정 수행]
                // ---------------------------------------------
                var loginUrl = ""
                
                C_FTP_NWConnection_Client_Module.FTP_SERTVER = server
                C_FTP_NWConnection_Client_Module.FTP_PORT = Int(port)
                
                //C_FTP_NWConnection_Client_Module.FTP_USER_NAME = userName.addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? ""
                //C_FTP_NWConnection_Client_Module.FTP_USER_PW = pw.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed) ?? ""
                
                C_FTP_NWConnection_Client_Module.FTP_USER_NAME = userName
                C_FTP_NWConnection_Client_Module.FTP_USER_PW = pw
                
                
                // ---------------------------------------------
                // MARK: [FTP 접속 URL 형식 지정 및 연결 요청 수행]
                // ---------------------------------------------
                // MARK: ftp://username:password@ftp.example.com:21
                // ---------------------------------------------
                loginUrl = "ftp://\(userName.addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? ""):\(pw.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed) ?? "")@\(server):\(port)"
                
                
                // [FTP 연결 옵션 지정]
                C_FTP_NWConnection_Client_Module.connection = NWConnection(to: .url(URL(string: loginUrl)!), using: self.parames)

                // [연결 상태 업데이트 핸들러 설정]
                C_FTP_NWConnection_Client_Module.connection?.stateUpdateHandler = { state in
                    switch state {
                    case .ready:
                        C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Success] : Connection Ready State"
                        
                        S_Log._W_(description: "FTP 연결 성공", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)",
                            "loginUrl :: \(loginUrl)"
                        ])
                        
                        // ---------------------------------------------
                        // MARK: [실시간 메시지 수신 상태 확인]
                        // ---------------------------------------------
                        // MARK: [receiveData 에서 사용자 로그인 처리 까지 완료 후 콜백 반환 수행]
                        // ---------------------------------------------
                        self.receiveData()
                        
                        
                    case .failed(let error):
                        C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Fail] : Connection Fail State"
                        
                        S_Log._E_(description: "FTP 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        if C_FTP_NWConnection_Client_Module.connectFlag == false {
                         
                            C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
                            
                        }
                        
                        // [객체 초기화]
                        if C_FTP_NWConnection_Client_Module.connection != nil {
                            
                            C_FTP_NWConnection_Client_Module.connection = nil
                            C_FTP_NWConnection_Client_Module.connectFlag = false
                            
                        }
                        
                        return
                        
                    case .cancelled:
                        C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Cancel] : Connection Cancel State"
                        
                        S_Log._E_(description: "FTP 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
                        ])
                        
                        // [콜백 반환]
                        if C_FTP_NWConnection_Client_Module.connectFlag == false {
                         
                            C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
                            
                        }
                        
                        // [객체 초기화]
                        if C_FTP_NWConnection_Client_Module.connection != nil {
                            
                            C_FTP_NWConnection_Client_Module.connection = nil
                            C_FTP_NWConnection_Client_Module.connectFlag = false
                            
                        }
                        
                        return
                        
                    default:
                        break
                    }
                }

                
                // [연결 시작]
                C_FTP_NWConnection_Client_Module.connection?.start(queue: .global())
                
                
                // ---------------------------------------------
                // MARK: [FTP 연결 타임 아웃 처리]
                // ---------------------------------------------
                self.workItem = DispatchWorkItem {
                    
                    if C_FTP_NWConnection_Client_Module.connection != nil && C_FTP_NWConnection_Client_Module.connectFlag == false {
                        
                        C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Time Out] : FTP Connection TimeOut"
                        
                        S_Log._E_(description: "FTP 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
                        ])
                        
                        // [FTP 연결 취소]
                        C_FTP_NWConnection_Client_Module.connection?.cancel()
                        
                    }
                    
                }
                
                let delay = DispatchTime.now() + self.CONNECT_TIME_OUT // [특정 시간 후에 실행]
                DispatchQueue.main.asyncAfter(deadline: delay, execute: self.workItem!)
                
            }
            else {
                C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Error] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 연결 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
                ])
                
                
                // [콜백 반환]
                C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
                return
                
            }
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : closeFtpConnect : FTP 연결 종료 수행
    // -----------------------------------------------------------------------------------------
    func closeFtpConnect() {
        
        if C_FTP_NWConnection_Client_Module.connection != nil {
            S_Log._E_(description: "FTP 연결 종료 수행 [IF]", data: nil)
            
            C_FTP_NWConnection_Client_Module.connection?.cancel()
            C_FTP_NWConnection_Client_Module.connection = nil
            C_FTP_NWConnection_Client_Module.connectFlag = false
        }
        else {
            S_Log._E_(description: "FTP 연결 종료 수행 [ELSE]", data: nil)
        }
        
    }
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : receiveData : 실시간 메시지 수신 상태 확인
    // -----------------------------------------------------------------------------------------
    static var RECEIVE_ERROR_LOG = ""
    private func receiveData() {
        
        if C_FTP_NWConnection_Client_Module.connection != nil {
            S_Log._D_(description: "RECEIVE 실시간 메시지 수신 감지 수행", data: nil)
            
            C_FTP_NWConnection_Client_Module.connection?.receive(minimumIncompleteLength: 1, maximumLength: 1024, completion: { data, _, isComplete, error in
                
                // -----------------------------------------------------------------------
                // MARK: [실시간 메시지 수신 확인]
                // -----------------------------------------------------------------------
                if let data = data, !data.isEmpty {
                    let message = String(data: data, encoding: .utf8) ?? ""
                    
                    S_Log._D_(description: "[Ing] ---- [RECEIVE 실시간 메시지 수신 감지] ---- [Ing]", data: [
                        "message :: \(message)"
                    ])
                    
                    
                    // ---------------------------------------------
                    // MARK: [220] : [로직 분기 처리] : FTP 서버 준비 완료 상태
                    // ---------------------------------------------

                    if message.trim().startsWith(_string: "220") == true {
                        
                        // MARK: [220 FTP Server ready.]
                        S_Log._W_(description: "FTP 서버 준비 완료 상태 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        // MARK: [FTP 로그인 사용자 인증 수행 실시]
                        C_FTP_NWConnection_Client_Module().observableUserAuth(){(sendResult) in
                            
                            S_Log._D_(description: "FTP 로그인 사용자 ID 인증 수행 확인", data: ["\(sendResult)"])

                            if sendResult == true {
                               
                            }
                            else {
                               S_Log._E_(description: "FTP 로그인 사용자 ID 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"])
                                
                                // [로그인 실패 콜백 처리]
                                self.loginCallbackReturn(returnValue: false)
                            }
                            
                        }
                        
                    }
                    // ---------------------------------------------
                    // MARK: [331] : [로직 분기 처리] : 사용자의 암호를 입력 하십시오
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "331") == true {
                     
                        // MARK: [331 사용자의 암호를 입력 하십시오.] : 사용자 ID 인증 성공
                        S_Log._W_(description: "FTP 서버 사용자 인증 완료 상태 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        // MARK: [FTP 로그인 사용자 PW 확인 실시]
                        C_FTP_NWConnection_Client_Module().observablePwAuth(){(sendResult) in
                            
                            S_Log._D_(description: "FTP 로그인 사용자 PW 인증 수행 확인", data: ["\(sendResult)"])

                            if sendResult == true {
                               
                            }
                            else {
                               S_Log._E_(description: "FTP 로그인 사용자 PW 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"])
                                
                                // [로그인 실패 콜백 처리]
                                self.loginCallbackReturn(returnValue: false)
                            }
                            
                        }
                    }
                    // ---------------------------------------------
                    // MARK: [530] : [로직 분기 처리] : 로그인에 실패했습니다
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "530") == true {
                        
                        // MARK: [530 로그인에 실패했습니다.] : 변수 초기화
                        S_Log._E_(description: "FTP 서버 ID, PW 인증 실패 상태 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        
                        // [로그인 실패 콜백 처리]
                        self.loginCallbackReturn(returnValue: false)
                        
                    }
                    // ---------------------------------------------
                    // MARK: [230] : [로직 분기 처리] : 사용자 로그인 성공
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "230") == true {
                        
                        // MARK: [230 사용자 로그인] : 변수 초기화
                        S_Log._W_(description: "FTP 서버 ID, PW 인증 성공 상태 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        
                        // [로그인 성공 콜백 처리]
                        self.loginCallbackReturn(returnValue: true)
                        
                    }
                    // ---------------------------------------------
                    // MARK: [200] I Type 설정 : 바이너리 모드 설정
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "200") == true {
                        
                        // MARK: [200 I Type 설정]
                        S_Log._W_(description: "FTP Type 바이너리 모드 설정 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        
                        // MARK: [FTP 파일 다운로드 패시브 모드 설정]
                        C_FTP_NWConnection_Client_Module().observablePassiveMode(){(sendResult) in
                            
                            S_Log._D_(description: "FTP 파일 다운로드 패시브 모드 확인", data: ["\(sendResult)"])

                            if sendResult == true {
                               
                            }
                            else {
                               S_Log._E_(description: "FTP 파일 다운로드 패시브 모드 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"])
                                
                                // [파일 다운로드 실패 콜백 처리]
                                self.downloadCallbackReturn(returnValue: false)
                            }
                            
                        }
                        
                    }
                    // ---------------------------------------------
                    // MARK: [227] : [로직 분기 처리] : Entering Passive Mode 패시브 모드 진입
                    // ---------------------------------------------
                    // MARK: 227 Entering Passive Mode (112,175,185,132,198,97).
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "227") == true {
                        
                        // MARK: [227 Entering Passive Mode 패시브 모드 진입]
                        S_Log._W_(description: "FTP Entering Passive Mode 패시브 모드 진입 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        
                        // MARK: [FTP 파일 다운로드를 수행하기 위한 정규식 사용 데이터 파싱 수행]
                        let regex = try! NSRegularExpression(pattern: "\\((.*?)\\)")
                        if let match = regex.firstMatch(in: message, range: NSRange(location: 0, length: message.count)) {
                            let params = (message as NSString).substring(with: match.range(at: 1)).split(separator: ",")
                            if params.count == 6 {
                                
                                let host = "\(params[0]).\(params[1]).\(params[2]).\(params[3])"
                                let port = (UInt16(params[4])! << 8) + UInt16(params[5])!
                                
                                S_Log._D_(description: "FTP 파일 다운로드를 위한 NEW 접속 정보 확인", data: [
                                    "host :: \(host)",
                                    "port :: \(port)"
                                ])
                                
                                C_FTP_NWConnection_Client_Module().observableNewDownloadConnection(server: host, port: port){(connectResult) in
                                    
                                    S_Log._D_(description: "NEW 파일 서버 연결 확인 수행", data: ["\(connectResult)"])

                                    if connectResult == true {
                                       
                                    }
                                    else {
                                        S_Log._E_(description: "NEW 파일 서버 연결 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"])
                                        
                                        // [파일 다운로드 실패 콜백 처리]
                                        self.downloadCallbackReturn(returnValue: false)
                                    }
                                    
                                }
                                
                            }
                        }
                        else {
                            C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : FTP File Download Ural Parse Error"
                            
                            S_Log._E_(description: "FTP 파일 다운로드 에러", data: [
                                "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"
                            ])
                            
                            // [파일 다운로드 실패 콜백 처리]
                            self.downloadCallbackReturn(returnValue: false)
                            
                        }
                        
                    }
                    // ---------------------------------------------
                    // MARK: [150] : [로직 분기 처리] : BINARY 모드로 데이터 연결 열기
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "150") == true {
                        
                        // MARK: [150 RETR 설정]
                        S_Log._W_(description: "FTP RETR 모드 설정 확인", data: [
                            "message :: \(message)"
                        ])
                        
                        
                        // MARK: [self.receiveFile() :: 실시간 파일 다운로드 리시버에서 파일 등록 처리]
                        
                    }
                    // ---------------------------------------------
                    // MARK: [226] : [로직 분기 처리] : 전송 완료 : 파일 다운로드
                    // ---------------------------------------------
                    if message.trim().startsWith(_string: "226") == true {
                        
                        // MARK: [226 전송 완료]
                        S_Log._W_(description: "FTP 파일 다운로드 전송 완료", data: [
                            "message :: \(message)"
                        ])
                        
                    }
                    // ---------------------------------------------
                    // MARK: [550] : 정규 파일이 아님 : 파일 디렉토리를 찾을 수 없음 : No such file or directory
                    // ---------------------------------------------
                    // MARK: 원격 서버에 실제 경로가 없거나, 파일 다운로드를 위한 절차를 모두 수행하지 않은 경우 발생
                    // ---------------------------------------------
                    /*
                    */
                    // ---------------------------------------------
                    
                }

                
                
                
                
                // -----------------------------------------------------------------------
                // MARK: [계속해서 실시간 메시지 수신 처리]
                // -----------------------------------------------------------------------
                if isComplete {
                    C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG = "[Error] : Connection closed by server"
                    
                    S_Log._E_(description: "RECEIVE 실시간 메시지 수신 감지 에러", data: [
                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG)"
                    ])
                    
                    // ---------------------------------------------
                    // MARK: [소켓 연결 종료 및 객체 초기화]
                    // ---------------------------------------------
                    C_FTP_NWConnection_Client_Module.connection?.cancel()
                    //C_FTP_NWConnection_Client_Module.connection = nil
                    //C_FTP_NWConnection_Client_Module.connectFlag = false
                    
                } else if let error = error {
                    C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG = "[Error] : let error catch"
                    
                    S_Log._E_(description: "RECEIVE 실시간 메시지 수신 감지 에러", data: [
                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG)",
                        "Description :: \(error)"
                    ])
                    
                    // ---------------------------------------------
                    // MARK: [소켓 연결 종료 및 객체 초기화]
                    // ---------------------------------------------
                    C_FTP_NWConnection_Client_Module.connection?.cancel()
                    //C_FTP_NWConnection_Client_Module.connection = nil
                    //C_FTP_NWConnection_Client_Module.connectFlag = false
                    
                } else {
                    
                    // ---------------------------------------------
                    // [계속해서 데이터 수신]
                    // ---------------------------------------------
                    self.receiveData()
                    
                }
            })
            
        }
        else {
            S_Log._D_(description: "소켓 실시간 메시지 수신 감지 에러 :: connection is null", data: nil)
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableUserAuth : FTP 사용자 ID 인증 요청 상태 확인
    // -----------------------------------------------------------------------------------------
    static var LOGIN_USER_ERROR_LOG = ""
    func observableUserAuth(completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableUserAuth 메소드 설명]
        // -----------------------------------------
        1. FTP 사용자 ID 인증 요청 상태 확인
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observableUserAuth(){(sendResult) in
             
             S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [변수 선언]
        C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = ""
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {
            S_Log._D_(description: "FTP 로그인 사용자 ID 인증 요청 수행", data: nil)
            
            // MARK: [인풋 데이터 널 체크 수행]
            if C_FTP_NWConnection_Client_Module.connection != nil
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true {
                
                
                let commandWithCRLF = "USER \(C_FTP_NWConnection_Client_Module.FTP_USER_NAME)" + "\r\n"
                
                C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                    if let error = error {
                        C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : FTP User Auth Error"
                        
                        S_Log._E_(description: "FTP 로그인 사용자 ID 인증 에러", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        completion(false)
                        return
                        
                    } else {
                        S_Log._W_(description: "FTP 로그인 사용자 ID 인증 성공", data: [
                            "commandWithIdCRLF :: \(commandWithCRLF)"
                        ])
                        
                        // [콜백 반환]
                        completion(true)
                        return
                        
                    }
                })
                
            }
            else {
                C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 로그인 사용자 ID 인증 수행 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"
                ])
                
                // [콜백 반환]
                completion(false)
                return
            }
            
        }

    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observablePwAuth : FTP 사용자 PW 인증 요청 상태 확인
    // -----------------------------------------------------------------------------------------
    static var LOGIN_PW_ERROR_LOG = ""
    func observablePwAuth(completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observablePwAuth 메소드 설명]
        // -----------------------------------------
        1. FTP 사용자 PW 인증 요청 상태 확인
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observablePwAuth(){(sendResult) in
             
             S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [변수 선언]
        C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = ""
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {
            S_Log._D_(description: "FTP 로그인 사용자 PW 인증 요청 수행", data: nil)

            // MARK: [인풋 데이터 널 체크 수행]
            if C_FTP_NWConnection_Client_Module.connection != nil
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true {
                
                
                let commandWithCRLF = "PASS \(C_FTP_NWConnection_Client_Module.FTP_USER_PW)" + "\r\n"
                
                C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                    if let error = error {
                        C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : FTP User Pw Error"
                        
                        S_Log._E_(description: "FTP 로그인 사용자 PW 인증 에러", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        completion(false)
                        return
                        
                    } else {
                        S_Log._W_(description: "FTP 로그인 사용자 PW 인증 성공", data: [
                            "commandWithPwCRLF :: \(commandWithCRLF)"
                        ])
                        
                        // [콜백 반환]
                        completion(true)
                        return
                        
                    }
                })
                
            }
            else {
                C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 로그인 사용자 PW 인증 수행 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"
                ])
                
                // [콜백 반환]
                completion(false)
                return
            }
            
        }

    }
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : loginCallbackReturn : FTP 로그인 콜백 처리 수행
    // -----------------------------------------------------------------------------------------
    func loginCallbackReturn(returnValue: Bool) {
        
        /*
        // -----------------------------------------
        [loginCallbackReturn 메소드 설명]
        // -----------------------------------------
        1. FTP 로그인 콜백 처리 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         self.loginCallbackReturn(returnValue: true)
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // -----------------------------------------
        // MARK: [True , Flase 에 맞게 변수 초기화 및 로직 처리 수행]
        // -----------------------------------------
        if returnValue == true { // MARK: [성공]
            S_Log._D_(description: "loginCallbackReturn :: 로그인 [성공] 콜백 처리 수행", data: nil)
            
            // [변수 값 초기화]
            C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = ""
            C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = ""
            
            
            // MARK: [작업 큐 값 변경 >> 로그인 성공 처리 수행]
            C_FTP_NWConnection_Client_Module.connectFlag = true
            C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
            
        }
        else { // MARK: [실패]
            S_Log._D_(description: "loginCallbackReturn :: 로그인 [실패] 콜백 처리 수행", data: nil)
            
            // [변수 값 추가]
            C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : Login Fail"
            C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : Login Fail"
            
            
            // MARK: [로그인 실패 처리 수행]
            if C_FTP_NWConnection_Client_Module.connection != nil && C_FTP_NWConnection_Client_Module.connectFlag == false {
                
                C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Login Auth] : FTP Login Fail"
                
                S_Log._E_(description: "FTP 연결 실패", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
                ])
                
                // [MQTT 연결 취소]
                C_FTP_NWConnection_Client_Module.connection?.cancel()
                
            }
            
        }

    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableUploadFile : 실시간 파일 업로드 수행
    // -----------------------------------------------------------------------------------------
    // 1. STOR 커맨드 사용해 파일 업로드 상태 전환
    // -----------------------------------------------------------------------------------------
    // 2. 앱 내부 로컬에 저장 된 파일 send 보내기 수행
    // -----------------------------------------------------------------------------------------
    static var UPLOAD_ERROR_LOG = ""
    func observableUploadFile(fileUrl:String, remoteUrl:String, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableUploadFile 메소드 설명]
        // -----------------------------------------
        1. FTP 실시간 파일 전송 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observableUploadFile(fileUrl:"file://..", remoteUrl:"/html/crash.txt"){(sendResult) in
             
             S_Log._F_(description: "FTP 실시간 파일 전송 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "FTP 실시간 파일 전송 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [변수 선언]
        C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = ""
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {
            S_Log._D_(description: "FTP 파일 업로드 요청 수행", data: nil)

            // MARK: [인풋 데이터 널 체크 수행]
            if C_FTP_NWConnection_Client_Module.connection != nil
                && C_Util().stringNotNull(str: fileUrl) == true
                && C_Util().stringNotNull(str: remoteUrl) == true {
                
                
                // MARK: [최종 로그인 커맨드까지 확인이 완료 되어야함] : LOGIN_USER_ERROR_LOG , LOGIN_PW_ERROR_LOG
                if C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_SERTVER) == true
                    && C_FTP_NWConnection_Client_Module.FTP_PORT > 0
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true
                    
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG) == false
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG) == false {
                    
                    
                    // MARK: [FTP 접속 URL 형식 선언]
                    var remoteFileUrl = ""
                    
                    if remoteUrl.startsWith(_string: "/") == false {
                        remoteFileUrl = "/" + remoteUrl
                    }
                    else {
                        remoteFileUrl = remoteUrl
                    }
                    
                    let loginUrl = "ftp://\(C_FTP_NWConnection_Client_Module.FTP_USER_NAME):\(C_FTP_NWConnection_Client_Module.FTP_USER_PW)@\(C_FTP_NWConnection_Client_Module.FTP_USER_NAME):\(C_FTP_NWConnection_Client_Module.FTP_PORT)\(remoteFileUrl)" // [파일 경로에는 시작이 / 필요]
                    
                    
                    S_Log._D_(description: "FTP 클라이언트 >> 서버 파일 업로드 수행", data: ["REMOTE_URL :: \(loginUrl)", "remoteFileUrl :: \(remoteFileUrl)", "LOCAL_FILE :: \(fileUrl)"])
                    
                    
                    // MARK: [연결 상태 업데이트 핸들러 설정]
                    let commandWithCRLF = "STOR \(remoteFileUrl)" + "\r\n"
                    
                    C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                        if let error = error {
                            C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = "[Error] : File Upload Command Error"
                            
                            S_Log._E_(description: "FTP 실시간 파일 전송 Command 에러", data: [
                                "M_LOG :: \(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)",
                                "Description :: \(error)"
                            ])
                            completion(false) // [콜백 반환]
                            return
                            
                        } else {
                            S_Log._W_(description: "FTP 실시간 파일 전송 Command 성공", data: [
                                "commandWithCRLF :: \(commandWithCRLF)"
                            ])
                            
                            // -----------------------------------------
                            // MARK: [파일 URL 지정 및 파일 업로드 수행]
                            // -----------------------------------------
                            //*

                            guard let fileData = try? Data(contentsOf: URL(string: fileUrl)!) else {
                                C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = "[Fail] : File Url Error"
                                
                                S_Log._E_(description: "FTP 파일 업로드 연결 실패", data: [
                                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)"
                                ])
                                
                                // [콜백 반환]
                                completion(false)
                                return
                            }
                            
                            
                            C_FTP_NWConnection_Client_Module.connection?.send(content: fileData, completion: .contentProcessed { error in
                                if let error = error {
                                    C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = "[Error] : File Upload Message Error"
                                    
                                    S_Log._E_(description: "FTP 실시간 파일 전송 에러", data: [
                                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)",
                                        "Description :: \(error)"
                                    ])
                                    completion(false) // [콜백 반환]
                                    return
                                    
                                } else {
                                    S_Log._W_(description: "FTP 실시간 파일 전송 성공", data: [
                                        "URL :: \(loginUrl)"
                                    ])
                                    completion(true) // [콜백 반환]
                                    return
                                    
                                }
                            })
                            // */
                            
                        }
                    })
                    
                }
                else {
                    
                    C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = "[Error] : FTP Login Info Error"
                    
                    S_Log._E_(description: "FTP 파일 업로드 전송 에러", data: [
                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)"
                    ])
                    completion(false) // [콜백 반환]
                    return
                    
                }
                
            }
            else {
                C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG = "[Error] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 실시간 파일 전송 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.UPLOAD_ERROR_LOG)"
                ])
                completion(false) // [콜백 반환]
                return
            }
            
        }

    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableDownloadFile : 실시간 파일 다운로드 수행
    // -----------------------------------------------------------------------------------------
    // 1. TYPE 커맨드 사용해 바이너리 업로드 상태 전환
    // -----------------------------------------------------------------------------------------
    // 2. PASV 커맨드 사용해 패시브 모드 상태 전환
    // -----------------------------------------------------------------------------------------
    // 3. 성공적으로 패시브 모드 전환 시 새롭게 내려온 NEW 서버 주소 파싱 수행 : Entering Passive Mode (112,175,185,132,198,97)
    // -----------------------------------------------------------------------------------------
    // 4. NWConnection 새롭게 생성 후 ready 상태로 진입 수행
    // -----------------------------------------------------------------------------------------
    // 5. PASV 커맨드 사용해 로그인 한 커넥션 객체로 send 메시지 전송 (파일 내려 주세요. 요청)
    // -----------------------------------------------------------------------------------------
    // 6. 신규 NWConnection 객체 reciveFile 리시버에서 파일 다운로드가 응답 되면 앱 내부에 파일 저장 수행
    // -----------------------------------------------------------------------------------------
    static var DOWNLOAD_ERROR_LOG = ""
    static var DOWNLOAD_REMOTE_URL = ""
    static var DOWNLOAD_LOCAL_URL = ""
    static var downloadOperationQueue = OperationQueue()
    
    func observableDownloadFile(remoteUrl:String, localFileName:String, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableUploadFile 메소드 설명]
        // -----------------------------------------
        1. FTP 실시간 파일 전송 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observableDownloadFile(remoteUrl: "/html/crash.txt", localFileName:"crash.txt"){(sendResult) in
             
             S_Log._F_(description: "FTP 실시간 파일 다운로드 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "FTP 실시간 파일 다운로드 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [변수 선언]
        C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = ""
        C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL = ""
        C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL = ""
        C_FTP_NWConnection_Client_Module.downloadFlag = false
        
        
        // MARK: [작업 큐에 추가]
        C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = true
        let block = { completion(C_FTP_NWConnection_Client_Module.downloadFlag) }
        C_FTP_NWConnection_Client_Module.downloadOperationQueue.addOperation(block)
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {
            S_Log._D_(description: "FTP 파일 다운로드 요청 수행", data: nil)

            // ------------------------------------------------
            // MARK: [인풋 데이터 널 체크 수행]
            // ------------------------------------------------
            if C_FTP_NWConnection_Client_Module.connection != nil
                && C_Util().stringNotNull(str: remoteUrl) == true
                && C_Util().stringNotNull(str: localFileName) == true {
                
                
                // ------------------------------------------------
                // MARK: [최종 로그인 커맨드까지 확인이 완료 되어야함] : LOGIN_USER_ERROR_LOG , LOGIN_PW_ERROR_LOG
                // ------------------------------------------------
                if C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_SERTVER) == true
                    && C_FTP_NWConnection_Client_Module.FTP_PORT > 0
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true
                    
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG) == false
                    && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG) == false {
                    
                    
                    // MARK: [FTP 접속 URL 형식 선언]
                    var remoteFileUrl = ""
                    
                    if remoteUrl.startsWith(_string: "/") == false {
                        remoteFileUrl = "/" + remoteUrl
                    }
                    else {
                        remoteFileUrl = remoteUrl
                    }
                    
                    
                    // ----------------------------------------------
                    // MARK: [다운로드 로직 처리를 위한 변수 값 삽입]
                    // ----------------------------------------------
                    C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL = localFileName
                    C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL = remoteFileUrl
                    
                    
                    let URL_DATA = "ftp://\(C_FTP_NWConnection_Client_Module.FTP_USER_NAME):\(C_FTP_NWConnection_Client_Module.FTP_USER_PW)@\(C_FTP_NWConnection_Client_Module.FTP_SERTVER):\(C_FTP_NWConnection_Client_Module.FTP_PORT)\(remoteFileUrl)" // [FTP 주소 지정 : 다운로드할 경로를 포함]
                    
                    
                    S_Log._D_(description: "FTP 클라이언트 >> 서버 파일 다운로드 수행", data: ["REMOTE_URL :: \(URL_DATA)"])
                    
                    
                    // ----------------------------------------------
                    // MARK: [바이너리 모드 설정] : [TYPE I]
                    // ----------------------------------------------
                    let commandWithCRLF = "TYPE I" + "\r\n"
                    
                    C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                        if let error = error {
                            C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [TYPE] : File Download Command Error"
                            
                            S_Log._E_(description: "FTP : 실시간 파일 다운로드 [TYPE] Command 에러", data: [
                                "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)",
                                "Description :: \(error)"
                            ])
                            
                            // [콜백 반환]
                            C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = false
                            return
                            
                        } else {
                            S_Log._W_(description: "FTP : 실시간 파일 다운로드 [TYPE] Command 성공", data: [
                                "commandWithCRLF :: \(commandWithCRLF)"
                            ])
                            
                            
                            // ----------------------------------------------
                            // MARK: [receiveData 에서 바이너리 모드 설정 상태 확인]
                            // ----------------------------------------------
                            
                        }
                    })
                    
                }
                else {
                    
                    C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [TYPE] : FTP Login Info Error"
                    
                    S_Log._E_(description: "FTP 파일 다운로드 에러", data: [
                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"
                    ])
                    
                    // [콜백 반환]
                    C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = false
                    return
                    
                }
                
            }
            else {
                C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [TYPE] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 파일 다운로드 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"
                ])
                
                // [콜백 반환]
                C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = false
                return
            }
            
        }

    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observablePassiveMode : 파일 다운로드 패시브 모드 수행
    // -----------------------------------------------------------------------------------------
    func observablePassiveMode(completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observablePassiveMode 메소드 설명]
        // -----------------------------------------
        1. 파일 다운로드 패시브 모드 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observablePassiveMode(){(sendResult) in
             
             S_Log._F_(description: "FTP 파일 다운로드 패시브 모드 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "FTP 파일 다운로드 패시브 모드 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {
            S_Log._D_(description: "FTP 파일 다운로드 패시브 모드 요청 수행", data: nil)

            // ------------------------------------------------
            // MARK: [인풋 데이터 널 체크 수행]
            // ------------------------------------------------
            // MARK: [최종 로그인 커맨드까지 확인이 완료 되어야함] : LOGIN_USER_ERROR_LOG , LOGIN_PW_ERROR_LOG
            // ------------------------------------------------
            // MARK: [파일 다운로드 바이너리 모드 요청이 완료 되어야함] : DOWNLOAD_REMOTE_URL , DOWNLOAD_LOCAL_URL
            // ------------------------------------------------
            if C_FTP_NWConnection_Client_Module.connection != nil
                
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_SERTVER) == true
                && C_FTP_NWConnection_Client_Module.FTP_PORT > 0
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true
                
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG) == false
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG) == false
                
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL) == true
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL) == true {
                
                
                // ----------------------------------------------
                // MARK: [패시브 모드 설정] : [PASV]
                // ----------------------------------------------
                let commandWithCRLF = "PASV" + "\r\n"
                
                C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                    if let error = error {
                        C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [PASV] : File Download Command Error"
                        
                        S_Log._E_(description: "FTP : 실시간 파일 다운로드 [PASV] Command 에러", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        completion(false)
                        return
                        
                    } else {
                        S_Log._W_(description: "FTP : 실시간 파일 다운로드 [PASV] Command 성공", data: [
                            "commandWithCRLF :: \(commandWithCRLF)"
                        ])
                        
                        
                        // ----------------------------------------------
                        // MARK: [receiveData 에서 패시브 모드 설정 상태 확인]
                        // ----------------------------------------------
                        
                    }
                })
                
            }
            else {
                C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [PASV] : Input Data Is Null"
                
                S_Log._E_(description: "FTP 파일 다운로드 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)"
                ])
                
                // [콜백 반환]
                completion(false)
                return
            }
            
        }

    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableNewDownloadConnection : 파일 다운로드 NEW 새로운 접속 수행
    // -----------------------------------------------------------------------------------------
    static var NEW_CONNECT_LOG = ""
    func observableNewDownloadConnection(server: String, port: UInt16, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableNewDownloadConnection 메소드 설명]
        // -----------------------------------------
        1. 파일 다운로드 NEW 새로운 접속 IP , PORT 사용해 FTP 연결 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_FTP_NWConnection_Client_Module().observableNewDownloadConnection(server: "128.165.0.4", port: 56123){(connectResult) in
             
             S_Log._F_(description: "NEW 파일 서버 연결 확인 수행", data: ["\(connectResult)"])

             if connectResult == true {
                
                // [FTP 연결 완료 로직 처리]
             }
             else {
                S_Log._F_(description: "NEW 파일 서버 연결 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */


        // [변수 선언 및 초기화]
        C_FTP_NWConnection_Client_Module.fileNwconnection = nil
        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = ""
        C_FTP_NWConnection_Client_Module.downloadFlag = false
        self.workItem = nil
        
        
        // [로직 처리 수행]
        DispatchQueue.main.async {
            S_Log._D_(description: "NEW FTP 파일 서버 연결 수행", data: [ "SERVER :: \(server)", "PORT :: \(port)" ])
            
            
            // ------------------------------------------------
            // MARK: [인풋 데이터 널 체크 수행]
            // ------------------------------------------------
            // MARK: [파일 다운로드 바이너리 모드 요청이 완료 되어야함] : DOWNLOAD_REMOTE_URL , DOWNLOAD_LOCAL_URL
            // ------------------------------------------------
            if C_Util().stringNotNull(str: server) == true && port >= 0
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL) == true
                && C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL) == true {
                
                
                // [FTP 연결 옵션 지정]
                C_FTP_NWConnection_Client_Module.fileNwconnection = NWConnection(host: NWEndpoint.Host(server), port: NWEndpoint.Port("\(port)")!, using: self.parames)

                // [연결 상태 업데이트 핸들러 설정]
                C_FTP_NWConnection_Client_Module.fileNwconnection?.stateUpdateHandler = { state in
                    switch state {
                    case .ready:
                        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Success] : New Connection Ready State"
                        
                        S_Log._W_(description: "NEW FTP 파일 서버 연결 성공", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                        ])
                        
                        
                        // ----------------------------------------------
                        // MARK: [실시간 파일 다운로드 수신 상태 확인]
                        // ----------------------------------------------
                        self.receiveFile()
                        
                        
                        // ---------------------------------------------
                        // MARK: [파일 다운로드 요청] : [RETR]
                        // ---------------------------------------------
                        // MARK: [SEND] : 요청 보내는 것은 로그인이 된 C_FTP_NWConnection_Client_Module.connection 로 요청 필요
                        // ---------------------------------------------
                        S_Log._D_(description: "FTP : 실시간 파일 다운로드 [RETR] Command 요청 수행", data: nil)
                        
                        let commandWithCRLF = "RETR \(C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL)" + "\r\n"
                        
                        C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
                            if let error = error {
                                C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG = "[Error] : [RETR] : File Download Command Error"
                                
                                S_Log._E_(description: "FTP : 실시간 파일 다운로드 [RETR] Command 에러", data: [
                                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.DOWNLOAD_ERROR_LOG)",
                                    "Description :: \(error)"
                                ])
                                
                                // [콜백 반환]
                                if C_FTP_NWConnection_Client_Module.downloadFlag == false {
                                 
                                    completion(false)
                                    
                                }
                                
                                // [객체 초기화]
                                if C_FTP_NWConnection_Client_Module.fileNwconnection != nil {
                                    
                                    C_FTP_NWConnection_Client_Module.fileNwconnection = nil
                                    C_FTP_NWConnection_Client_Module.downloadFlag = false
                                    
                                }
                                
                                return
                                
                            } else {
                                S_Log._W_(description: "FTP : 실시간 파일 다운로드 [RETR] Command 성공", data: [
                                    "commandWithCRLF :: \(commandWithCRLF)"
                                ])
                                
                                // ----------------------------------------------
                                // MARK: [receiveData 에서 파일 다운로드 요청 상태 확인] : [150 BINARY 모드로 데이터 연결 열기]
                                // ----------------------------------------------
                                C_FTP_NWConnection_Client_Module.downloadFlag = true
                                
                            }
                        })
                        
                        
                    case .failed(let error):
                        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Fail] : New Connection Fail State"
                        
                        S_Log._E_(description: "NEW FTP 파일 서버 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        if C_FTP_NWConnection_Client_Module.downloadFlag == false {
                         
                            completion(false)
                            
                        }
                        
                        // [객체 초기화]
                        if C_FTP_NWConnection_Client_Module.fileNwconnection != nil {
                            
                            C_FTP_NWConnection_Client_Module.fileNwconnection = nil
                            C_FTP_NWConnection_Client_Module.downloadFlag = false
                            
                        }
                        
                        return
                        
                    case .cancelled:
                        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Cancel] : Connection Cancel State"
                        
                        S_Log._E_(description: "NEW FTP 파일 서버 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                        ])
                        
                        // [콜백 반환]
                        if C_FTP_NWConnection_Client_Module.downloadFlag == false {
                         
                            completion(false)
                            
                        }
                        
                        // [객체 초기화]
                        if C_FTP_NWConnection_Client_Module.fileNwconnection != nil {
                            
                            C_FTP_NWConnection_Client_Module.fileNwconnection = nil
                            C_FTP_NWConnection_Client_Module.downloadFlag = false
                            
                        }
                        
                        return
                        
                    default:
                        break
                    }
                }

                
                // [연결 시작]
                C_FTP_NWConnection_Client_Module.fileNwconnection?.start(queue: .global())
                
                
                // ---------------------------------------------
                // MARK: [FTP 연결 타임 아웃 처리]
                // ---------------------------------------------
                self.workItem = DispatchWorkItem {
                    
                    if C_FTP_NWConnection_Client_Module.fileNwconnection != nil && C_FTP_NWConnection_Client_Module.downloadFlag == false {
                        
                        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Time Out] : New FTP Connection TimeOut"
                        
                        S_Log._E_(description: "NEW FTP 파일 서버 연결 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                        ])
                        
                        // [FTP 연결 취소]
                        C_FTP_NWConnection_Client_Module.fileNwconnection?.cancel()
                        
                    }
                    
                }
                
                let delay = DispatchTime.now() + self.CONNECT_TIME_OUT // [특정 시간 후에 실행]
                DispatchQueue.main.asyncAfter(deadline: delay, execute: self.workItem!)
                
            }
            else {
                C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Error] : New Input Data Is Null"
                
                S_Log._E_(description: "NEW FTP 파일 서버 연결 에러", data: [
                    "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                ])
                
                
                // [콜백 반환]
                completion(false)
                return
                
            }
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : receiveFile : 실시간 파일 다운로드 수신 상태 확인
    // -----------------------------------------------------------------------------------------
    private func receiveFile() {
        
        if C_FTP_NWConnection_Client_Module.fileNwconnection != nil {
            S_Log._D_(description: "RECEIVE 실시간 파일 다운로드 수신 감지 수행", data: nil)
            
            C_FTP_NWConnection_Client_Module.fileNwconnection?.receive(minimumIncompleteLength: 1, maximumLength: 4096, completion: { data, _, isComplete, error in
                
                // -----------------------------------------------------------------------
                // MARK: [FTP 연결 종료 및 객체 초기화]
                // -----------------------------------------------------------------------
                C_FTP_NWConnection_Client_Module.fileNwconnection?.cancel()
                //C_FTP_NWConnection_Client_Module.fileNwconnection = nil
                //C_FTP_NWConnection_Client_Module.downloadFlag = false
                
                
                // -----------------------------------------------------------------------
                // MARK: [앱 로컬 저장소에 파일 저장 수행]
                // -----------------------------------------------------------------------
                if let data = data, !data.isEmpty {
                    
                    if C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL) == true {
                        S_Log._W_(description: "[Ing] ---- [RECEIVE 실시간 파일 다운로드 수신 감지] ---- [Ing]", data: nil)
                        
                        // -----------------------------------------
                        // MARK: [로컬 앱 파일 저장 경로 지정 수행]
                        // -----------------------------------------
                        // MARK:
                        // -----------------------------------------
                        let fileManager = FileManager.default // 파일 매니저 선언
                        let documentsUrl =  fileManager.urls(for: .documentDirectory, in: .userDomainMask).first // 기본 경로 확인
                        let fileName = C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL
                        
                        var filePath = documentsUrl?.path ?? ""
                        if (filePath.hasSuffix("/") == true){
                            filePath = filePath + fileName
                        }
                        else {
                            filePath = filePath + "/" + fileName
                        }
                        
                        
                        // -----------------------------------------
                        // MARK: [로컬 앱 파일 저장 수행]
                        // -----------------------------------------
                        if FileManager.default.fileExists(atPath: filePath) == true { // [파일 존재]
                            
                            let contentData = data
                            
                            if let handle = try? FileHandle(forWritingTo: NSURL.fileURL(withPath: filePath)) {
                                handle.seekToEndOfFile() // moving pointer to the end
                                handle.write(contentData) // adding content
                                handle.closeFile() // closing the file
                                
                                C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Success] :: [Append] :: File"
                            }
                            else {
                                C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Fail] :: [Append] :: File"
                            }
                            
                        }
                        else { // [파일 없음]
                            do {
                                let contentData = data
                                
                                try contentData.write(to: NSURL.fileURL(withPath: filePath), options: Data.WritingOptions.atomic)
                                
                                C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Success] :: [Write] :: File"
                                        
                            } catch {
                                C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Exception] :: [Write] :: \(error.localizedDescription)"
                            }
                        }
                        
                        
                        S_Log._W_(description: "FTP 파일 앱 저장 수행 성공", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                        ])
                        
                        
                        // ---------------------------------------------
                        // MARK: [FTP 파일 다운로드 성공 콜백 반환]
                        // ---------------------------------------------
                        self.downloadCallbackReturn(returnValue: true)
                        
                    }
                    else {
                        C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Error] : DOWNLOAD_LOCAL_URL Is Null"
                        
                        S_Log._E_(description: "FTP 파일 앱 저장 수행 실패", data: [
                            "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                        ])
                        
                        
                        // ---------------------------------------------
                        // MARK: [FTP 파일 다운로드 실패 콜백 반환]
                        // ---------------------------------------------
                        self.downloadCallbackReturn(returnValue: false)
                        
                    }
                    
                }
                else {
                    S_Log._E_(description: "[Empty] ---- [RECEIVE 실시간 파일 다운로드 수신 감지] ---- [Empty]", data: nil)
                    
                    C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG = "[Error] : File Size Is Null"
                    
                    S_Log._E_(description: "FTP 파일 앱 저장 수행 실패", data: [
                        "M_LOG :: \(C_FTP_NWConnection_Client_Module.NEW_CONNECT_LOG)"
                    ])
                    
                    
                    // ---------------------------------------------
                    // MARK: [FTP 파일 다운로드 실패 콜백 반환]
                    // ---------------------------------------------
                    self.downloadCallbackReturn(returnValue: false)
                }
                
            })
            
        }
        else {
            S_Log._E_(description: "소켓 실시간 메시지 수신 감지 에러 :: connection is null", data: nil)
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : downloadCallbackReturn : FTP 파일 다운로드 콜백 처리 수행
    // -----------------------------------------------------------------------------------------
    func downloadCallbackReturn(returnValue: Bool) {
        
        /*
        // -----------------------------------------
        [downloadCallbackReturn 메소드 설명]
        // -----------------------------------------
        1. FTP 파일 다운로드 콜백 처리 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         self.downloadCallbackReturn(returnValue: true)
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // -----------------------------------------
        // MARK: [True , Flase 에 맞게 변수 초기화 및 로직 처리 수행]
        // -----------------------------------------
        if returnValue == true { // MARK: [성공]
            S_Log._D_(description: "downloadCallbackReturn :: 파일 다운로드 [성공] 콜백 처리 수행", data: nil)
            
            // [변수 값 초기화]
            C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL = ""
            C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL = ""
            
            
            // MARK: [작업 큐 값 변경 >> 로그인 성공 처리 수행]
            C_FTP_NWConnection_Client_Module.downloadFlag = true
            C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = false
            
        }
        else { // MARK: [실패]
            S_Log._D_(description: "downloadCallbackReturn :: 파일 다운로드 [실패] 콜백 처리 수행", data: nil)
            
            // [변수 값 추가]
            C_FTP_NWConnection_Client_Module.DOWNLOAD_LOCAL_URL = ""
            C_FTP_NWConnection_Client_Module.DOWNLOAD_REMOTE_URL = ""
            
            
            // MARK: [작업 큐 값 변경 >> 파일 다운로드 실패 처리 수행]
            C_FTP_NWConnection_Client_Module.downloadFlag = false
            C_FTP_NWConnection_Client_Module.downloadOperationQueue.isSuspended = false
            
        }

    }
    

    
} // [클래스 종료]

 

반응형
Comments