프로그래밍/파이썬

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

말춘이 2020. 2. 22. 15:32
반응형

 

 

GitHub - malchooni/EBestAPI_Python: 파이썬 학습목적의 이베스트 API 구현

파이썬 학습목적의 이베스트 API 구현. Contribute to malchooni/EBestAPI_Python development by creating an account on GitHub.

github.com

 

 

[파이썬] 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과 이것을 상속받아 구현하는 요청 클래스들을 구현해보겠다.

 

 

buycycle.name

'Buycycle'은 증권사 API를 HTTP Json으로 요청 및 응답 받을 수 있습니다. 요청 받은 Json 메시지를 증권사 API 양식에 맞게 변환해 주는 자바 기반의 오픈 소스 입니다. HTTP RESTful을 제공함으로써 사용자

buycycle.name

반응형