[파이썬] eBest Xing api 실시간조회, ConnectionManager 구현 (4)
[파이썬] 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과 이것을 상속받아 구현하는 요청 클래스들을 구현해보겠다.