ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [파이썬] eBest Xing api 실시간조회, ConnectionManager 구현 (4)
    프로그래밍/파이썬 2020. 2. 22. 15:32

    https://github.com/yalsooni/EBestAPI_Python

     

    [파이썬] eBest Xing api 실시간조회, 멀티스레드 설계 (1)

    [파이썬] eBest Xing api 실시간조회, 스레드 설계 구현 (2)

    [파이썬] eBest Xing api 실시간조회, ThreadJob 구현 (3)

    [파이썬] eBest Xing api 실시간조회, ConnectionManager 구현 (4)

    [파이썬] eBest Xing api 실시간조회, QueryThreadJob 구현 (5)

    [파이썬] eBest Xing api 실시간조회, NWS 뉴스 요청 구현 (6)

    [파이썬] eBest Xing api 실시간조회, S3_ 코스피체결 구현 (7)

    [파이썬] eBest Xing api 실시간조회, 테스트 및 실행 화면 (8)

     

     

      ConnectionManager 구현에 앞서 이베스트와 커넥션을 담당하는 XAConnector부터 구현하도록 하겠다.
      XAConnector클래스는 이베스트에서 제공하는 API 중 커넥션과 로그인 관련 요청과 응답을 구현한 것이다. 프로세스가 기동 되면 ConnectionManager 스레드가 시작되며 XAConnector 참조하여 연결을 관리하는 역할을 한다.

     

    import pythoncom
    import win32com.client as win_client
     
    from name_yalsooni.crawler_py.ebest.util import Log
     
     
    class XASessionEventHandler:
        login_state = 0
        connect_state = 0
        login_flag = False
     
        def OnLogin(self, code, msg):
            if code == "0000":
                Log.write("login success")
                Log.write(str(msg))
                XASessionEventHandler.login_flag = True
                XASessionEventHandler.login_state = 1
                XASessionEventHandler.connect_state = 1
            else:
                Log.write("login fail")
                Log.write(str(msg))
                XASessionEventHandler.login_state = 2
     
        def OnDisconnect(self):
            XASessionEventHandler.login_flag = False
            XASessionEventHandler.login_state = 0
            XASessionEventHandler.connect_state = 0
            Log.write("Disconnect Server")
     
     
    class XAConnector:
        __ebest_address = "hts.ebestsec.co.kr"
        __ebest_port = 20001
        __ebest_id = "이베스트 아이디"
        __ebest_pw = "이베스트 패스워드"
        __ebest_cpwd = "공인인증서 패스워드"
     
        __xa_session = None
     
        def connect_server(self):
            if self.__xa_session is None:
                self.__xa_session = win_client.DispatchWithEvents("XA_Session.XASession", XASessionEventHandler)
            return self.__xa_session.ConnectServer(self.__ebest_address, self.__ebest_port)
     
        def is_connected(self):
            if self.__xa_session is None:
                result = False
            else:
                result = self.__xa_session.IsConnected()
            return result
     
        def login(self):
            if not XASessionEventHandler.login_flag:
                self.__xa_session.Login(self.__ebest_id, self.__ebest_pw, self.__ebest_cpwd, 0, 0)
                while XASessionEventHandler.login_state == 0:
                    pythoncom.PumpWaitingMessages()
            return XASessionEventHandler.login_flag
     
        def get_account_list(self):
            account_list = []
            account_ctn = self.__xa_session.GetAccountListCount()
     
            for i in range(account_ctn):
                account_num = self.__xa_session.GetAccountList(i)
                account_list.append(account_num)
            return account_list
     
        def disconnect_server(self):
            if XASessionEventHandler.login_flag:
                self.__xa_session.DisconnectServer()
                XASessionEventHandler.login_state = 0
                XASessionEventHandler.connect_state = 0

     

    - 12 Line : OnLogin 메소드
      이벤트 핸들러의 OnLogin 메소드는 로그인 요청에 대한 응답 이벤트이다.
      code에 대한 값이 '0000'이면 로그인이 정상적으로 처리 됐다는 의미다.
    - 24 Line : OnDisconnect 메소드
      이벤트 핸들러의 OnDisconnect 메소드는 연결해제에 대한 응답 이벤트이다.
    - 40 Line : connect_server 메소드
      XA_Session.XASession 객체를 얻어와 이베스트서버에 커넥션을 연결한다.
      연결이 완료되면 True값을 반환한다.
    - 44 Line : is_connected 메소드
      현재 커넥션이 유효한 상태인지 확인할 수 있는 메소드이다.
      정상적인 커넥션이라면 True 값을 반환한다.
      각 쿼리들이 요청 전 해당커넥션이 유효한지 물을 때 사용된다.
    - 51 Line : login 메소드
      정상적으로 연결된 후 로그인을 요청할 수 있는 메소드이다.
      파라미터 값으로 아이디, 패스워드, 공인인증서 패스워드가 입력되며 로그인에 대한 결과는 이벤트 핸들러의 OnLogin 메소드가 호출된다.
    - 58 Line : get_account_list 메소드
      로그인이 완료되면 자신의 계좌목록을 얻어 올 수 있다.
    - 67 Line : disconnect_server 메소드
      이베스트 서버와의 연결을 끊는다.

     

      XAConnector클래스를 참조하는 ConnectionManager클래스를 구현해보도록 하겠다.
      ConnectionManager의 객체는 하나만 두기 위해 ConnectionManagerFactory클래스에서 싱글톤으로 사용한다.

     

    import threading
    import time
     
    from name_yalsooni.crawler_py.ebest.xasession import XAConnector
    from name_yalsooni.crawler_py.ebest.xasession import XASessionEventHandler
    from name_yalsooni.crawler_py.ebest.util import Log
    from name_yalsooni.crawler_py.ebest.definition import ThreadJob
     
     
    # 연결 관리
    class ConnectionManager(ThreadJob):
     
        _CM_LOGIN = "LOGIN"
        _CM_LOGOUT = "LOGOUT"
     
        _xa_connector = None
        _login_result = None
     
        def __init__(self):
            ThreadJob.__init__(self, "ConnectionManager", 10)
            self.lock = threading.Lock()
     
        # 스레드 초기화
        def _init(self):
            Log.write("ConnectionManager init..")
            self._xa_connector = XAConnector()
     
        # 스레드 수행
        def _execute(self, command):
            with self.lock:
                if command[self.CM_COMMAND] == self._CM_LOGIN:
                    self._xa_connect()
                elif command[self.CM_COMMAND] == self._CM_LOGOUT:
                    self._xa_disconnect()
     
        # 스레드 종료
        def _shutdown(self):
            pass
     
        # 연결 하기
        def _xa_connect(self):
            if self._xa_connector.is_connected() is False:
                self._xa_connector.connect_server()
                self._login_result = self._xa_connector.login()
                # if self.__login_result:
                    # account_list = self.__xa_connector.get_account_list()
                    # for account in account_list:
                    #     Log.write("account number : " + account)
     
            return self._login_result
     
        # 연결 해제
        def _xa_disconnect(self):
            self._xa_connector.disconnect_server()
     
        # 연결 응답 대기
        def _waiting_login(self):
            while XASessionEventHandler.login_state == 0:
                time.sleep(0.2)
     
        # 연결 해제 응답 대기
        def _waiting_logout(self):
            while XASessionEventHandler.login_state != 0:
                time.sleep(0.2)
     
        # 연결 요청
        def login_call(self):
            command = dict()
            command[self.CM_COMMAND] = self._CM_LOGIN
            self._push_command(command)
            self._waiting_login()
     
        # 연결 해제 요청
        def disconnect_call(self):
            command = dict()
            command[self.CM_COMMAND] = self._CM_LOGOUT
            self._push_command(command)
            self._waiting_logout()
     
     
    class ConnectionManagerFactory:
     
        _connection_manager = ConnectionManager()
     
        @staticmethod
        def get_instance():
            return ConnectionManagerFactory._connection_manager

     

    - 19 Line : __init__
      앞서 구현된 ThreadJob 생성자를 확인하면,파라미터 값으로 스레드 이름과 Queue.get의 타임아웃 값을 넣어줘야 한다.
      threading.Lock() 객체를 생성하는 이유는 로그인과 로그아웃 메소드의 순차처리를 위해서다.
    - 26 Line
      맨 위에서 구현된 XAConnector의 객체를 스레드 초기화 구문에서 생성한다.
    - 67 Line : login_call 메소드
      로그인 명령어를 큐에 삽입 후 _waiting_login 메소드를 통해 이벤트리스너가 수신받기 전까지 기다린다.
    - 74 Line : disconnect_call 메소드
      로그아웃 명령어를 큐에 삽입 후 _waiting_logout 메소드를 통해 이벤트리스너가 수신받기 전까지 기다린다.
    - 86 Line : get_instance 메소드
      ConnectionManager 객체를 싱글톤으로 사용한다.

     

      이렇게 구현된 ConnectionManager는 모든 정보조회 요청의 상위 클래스인 QueryThreadJob에서 참조한다.
      이제 QueryThreadJob과 이것을 상속받아 구현하는 요청 클래스들을 구현해보겠다.

    댓글 0

Designed by Tistory.