def __init__(self, control, host=None, port=None, max_workers=None): if host is None: host = config.get_string('koapy.backend.kiwoom_open_api_plus.grpc.host', 'localhost') if port is None: port = config.get('koapy.backend.kiwoom_open_api_plus.grpc.port') if port == 0: port = get_free_localhost_port() if max_workers is None: max_workers = config.get_int('koapy.backend.kiwoom_open_api_plus.grpc.server.max_workers', 8) self._control = control self._host = host self._port = port self._max_workers = max_workers self._address = self._host + ':' + str(self._port) self._servicer = KiwoomOpenApiPlusServiceServicer(self._control) self._executor = futures.ThreadPoolExecutor(max_workers=self._max_workers) self._server = None self._server_started = False self._server_stopped = False self.reinitialize_server() atexit.register(self._executor.shutdown, False)
def is_ready(self, timeout=None): if timeout is None: timeout = config.get_int('koapy.backend.kiwoom_open_api_plus.grpc.client.is_ready.timeout', 10) try: grpc.channel_ready_future(self._channel).result(timeout=timeout) return True except grpc.FutureTimeoutError: return False
def __init__(self, port=None, client_check_timeout=None, verbosity=None, log_level=None): self._port = port or config.get( 'koapy.grpc.port') or get_free_localhost_port() self._client_check_timeout = client_check_timeout self._verbosity = verbosity if log_level is None: if self._verbosity is not None: log_level = verbosity_to_loglevel(self._verbosity) self._log_level = log_level if self._log_level is not None: set_loglevel(self._log_level) self._server_proc_args = [ 'python', '-m', 'koapy.pyqt5.tools.start_tray_application', '--port', str(self._port) ] if self._verbosity: self._server_proc_args.append('-' + 'v' * self._verbosity) self._server_proc = None self._server_proc_terminate_timeout = config.get_int( 'koapy.grpc.context.server.terminate.timeout', 10) self._client = KiwoomOpenApiServiceClient(port=self._port) logging.debug('Testing if client is ready...') if not self._client.is_ready(client_check_timeout): logging.debug('Client is not ready, creating a new server') self._server_proc = subprocess.Popen(self._server_proc_args) assert self._client.is_ready() self._stub = self._client.get_stub() else: logging.debug('Client is ready, using existing server') self._stub = self._client.get_stub() self._lock = threading.RLock() self._enter_count = 0
def __init__(self, port=None, client_check_timeout=None, verbosity=None, log_level=None): if port is None: port = config.get('koapy.backend.kiwoom_open_api_plus.grpc.port', 0) or get_free_localhost_port() if log_level is None and verbosity is not None: log_level = verbosity_to_loglevel(verbosity) if verbosity is None and log_level is not None: verbosity = loglevel_to_verbosity(log_level) self._port = port self._client_check_timeout = client_check_timeout self._verbosity = verbosity self._log_level = log_level if self._log_level is not None: set_loglevel(self._log_level) self._server_executable = config.get('koapy.context.server.executable', None) if not isinstance(self._server_executable, str): self._server_executable = None if self._server_executable is None: envpath = config.get('koapy.context.server.executable.conda.envpath', None) if envpath is not None and isinstance(envpath, str): self._server_executable = subprocess.check_output([ # pylint: disable=unexpected-keyword-arg 'conda', 'run', '-p', envpath, 'python', '-c', 'import sys; print(sys.executable)', ], encoding=sys.stdout.encoding, creationflags=subprocess.CREATE_NO_WINDOW).strip() if self._server_executable is None: envname = config.get('koapy.context.server.executable.conda.envname', None) if envname is not None and isinstance(envname, str): self._server_executable = subprocess.check_output([ # pylint: disable=unexpected-keyword-arg 'conda', 'run', '-n', envname, 'python', '-c', 'import sys; print(sys.executable)', ], encoding=sys.stdout.encoding, creationflags=subprocess.CREATE_NO_WINDOW).strip() if self._server_executable is None: self._server_executable = sys.executable self._server_proc_args = [self._server_executable, '-m', 'koapy.cli', 'serve'] if self._port is not None: self._server_proc_args.extend(['-p', str(self._port)]) if self._verbosity is not None: self._server_proc_args.extend(['-' + 'v' * self._verbosity]) self._server_proc = None self._server_proc_terminate_timeout = config.get_int('koapy.context.server.terminate.timeout', 10) self._client = KiwoomOpenApiPlusServiceClient(port=self._port) self.logger.debug('Testing if client is ready...') if not self._client.is_ready(self._client_check_timeout): assert platform.architecture()[0] == '32bit', 'Server should run under 32bit environment' self.logger.debug('Client is not ready, creating a new server') self._server_proc = subprocess.Popen(self._server_proc_args) assert self._client.is_ready(), 'Failed to create server' self._stub = self._client.get_stub() else: self.logger.debug('Client is ready, using existing server') self._stub = self._client.get_stub() self._context_lock = threading.RLock() self._enter_count = 0
def __init__(self, port=None, client_check_timeout=None, verbosity=None, log_level=None): if port is None: port = (config.get("koapy.backend.kiwoom_open_api_plus.grpc.port", 0) or get_free_localhost_port()) if log_level is None and verbosity is not None: log_level = verbosity_to_loglevel(verbosity) if verbosity is None and log_level is not None: verbosity = loglevel_to_verbosity(log_level) self._port = port self._client_check_timeout = client_check_timeout self._verbosity = verbosity self._log_level = log_level if self._log_level is not None: set_loglevel(self._log_level) self._server_executable = config.get("koapy.context.server.executable", None) if not isinstance(self._server_executable, str): self._server_executable = None if self._server_executable is None: envpath = config.get( "koapy.context.server.executable.conda.envpath", None) if envpath is not None and isinstance(envpath, str): self._server_executable = subprocess.check_output( [ # pylint: disable=unexpected-keyword-arg "conda", "run", "-p", envpath, "python", "-c", "import sys; print(sys.executable)", ], encoding=sys.stdout.encoding, creationflags=subprocess.CREATE_NO_WINDOW, ).strip() if self._server_executable is None: envname = config.get( "koapy.context.server.executable.conda.envname", None) if envname is not None and isinstance(envname, str): self._server_executable = subprocess.check_output( [ # pylint: disable=unexpected-keyword-arg "conda", "run", "-n", envname, "python", "-c", "import sys; print(sys.executable)", ], encoding=sys.stdout.encoding, creationflags=subprocess.CREATE_NO_WINDOW, ).strip() if self._server_executable is None: self._server_executable = sys.executable self._server_proc_args = [ self._server_executable, "-m", "koapy.cli", "serve" ] if self._port is not None: self._server_proc_args.extend(["-p", str(self._port)]) if self._verbosity is not None: self._server_proc_args.extend(["-" + "v" * self._verbosity]) self._server_proc = None self._server_proc_terminate_timeout = config.get_int( "koapy.context.server.terminate.timeout", 10) self._client = KiwoomOpenApiPlusServiceClient(port=self._port) self.logger.debug("Testing if client is ready...") if not self._client.is_ready(self._client_check_timeout): assert (platform.architecture()[0] == "32bit" ), "Server should run under 32bit environment" self.logger.debug("Client is not ready, creating a new server") self._server_proc = subprocess.Popen(self._server_proc_args) assert self._client.is_ready(), "Failed to create server" self._stub = self._client.get_stub() else: self.logger.debug("Client is ready, using existing server") self._stub = self._client.get_stub() self._context_lock = threading.RLock() self._enter_count = 0
class KiwoomOpenApiPlusServiceClientSideSignalConnector: _lock = threading.RLock() _observers = {} _max_workers = config.get_int( 'koapy.backend.kiwoom_open_api_plus.grpc.client.signal_connector.max_workers', 8) _executor = futures.ThreadPoolExecutor(max_workers=_max_workers) def __init__(self, stub, name): self._stub = stub self._name = name @classmethod def _stop_observer(cls, observer): request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest() observer.on_next(request) observer.on_completed() def _get_observer(self, callback, default=None): return self._observers.setdefault(self._stub, {}).setdefault( self._name, {}).get(callback, default) def _remove_observer(self, callback): with self._lock: observer = self._get_observer(callback) if observer: self._stop_observer(observer) del self._observers[self._stub][self._name][callback] return observer def _add_observer(self, callback): with self._lock: self._remove_observer(callback) observer = QueueBasedIterableObserver() self._observers[self._stub][self._name][callback] = observer return observer @classmethod def shutdown(cls): with cls._lock: for _stub, names in cls._observers.items(): for _name, observers in names.items(): for _callback, observer in observers.items(): cls._stop_observer(observer) cls._executor.shutdown(False) def connect(self, callback): with self._lock: observer = self._add_observer(callback) def fn(): request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest( ) request.listen_request.slots.append(self._name) # pylint: disable=no-member observer.on_next(request) observer_iterator = iter(observer) for i, response in enumerate( self._stub.BidirectionalListen(observer_iterator)): # pylint: disable=unused-variable args = convert_arguments_from_protobuf_to_python( response.arguments) callback(*args) request = KiwoomOpenApiPlusService_pb2.BidirectionalListenRequest( ) observer.on_next(request) future = self._executor.submit(fn) def done(future): err = future.exception() if err: raise err future.add_done_callback(done) def disconnect(self, callback): with self._lock: self._remove_observer(callback)