def list_files( self, *specification: 'Union[FileSpecification, str]', ) -> 'List[str]': """ Получение списка файлов с сервера. :param specification: Спецификация или маска имени файла (если нужны файлы, лежащие в папке текущей базы данных) :return: Список файлов """ if not self.check_connection(): return [] query = ClientQuery(self, LIST_FILES) is_ok = False for spec in specification: if isinstance(spec, str): spec = self.near_master(spec) query.ansi(str(spec)) is_ok = True result: 'List[str]' = [] if not is_ok: return result with self.execute(query) as response: lines = response.ansi_remaining_lines() lines = [line for line in lines if line] for line in lines: result.extend(one for one in irbis_to_lines(line) if one) return result
def connect(self, host: 'Optional[str]' = None, port: int = 0, username: '******' = None, password: '******' = None, database: 'Optional[str]' = None) -> IniFile: """ Подключение к серверу ИРБИС64. :return: INI-файл """ if self.connected: return self.ini_file self.host = host or self.host or throw_value_error() self.port = port or self.port or int(throw_value_error()) self.username = username or self.username or throw_value_error() self.password = password or self.password or throw_value_error() self.database = self._get_database(database) assert isinstance(self.host, str) assert isinstance(self.port, int) assert isinstance(self.username, str) assert isinstance(self.password, str) while True: self.query_id = 0 self.client_id = random.randint(100000, 999999) query = ClientQuery(self, REGISTER_CLIENT) query.ansi(self.username).ansi(self.password) with self.execute(query) as response: if response.get_return_code() == -3337: continue return self._connect(response)
def disconnect(self) -> None: """ Отключение от сервера. :return: None. """ if self.connected: query = ClientQuery(self, UNREGISTER_CLIENT) query.ansi(self.username) self.execute_forget(query) self.connected = False
def execute_ansi(self, *commands) -> ServerResponse: """ Простой запрос к серверу, когда все строки запроса в кодировке ANSI. :param commands: Команда и параметры запроса :return: Ответ сервера (не забыть закрыть!) """ query = ClientQuery(self, commands[0]) for line in commands[1:]: query.ansi(line) return self.execute(query)
async def disconnect_async(self) -> None: """ Асинхронное отключение от сервера. :return: None. """ if self.connected: query = ClientQuery(self, UNREGISTER_CLIENT) query.ansi(self.username) response = await self.execute_async(query) response.close() self.connected = False
def _search_begin(self, parameters: 'Any') -> ClientQuery: if not isinstance(parameters, SearchParameters): parameters = SearchParameters(str(parameters)) query = ClientQuery(self, SEARCH) parameters.encode(query, self) return query
def list_processes(self) -> 'List[Process]': """ Получение списка серверных процессов. :return: Список процессов """ if not self.check_connection(): return [] query = ClientQuery(self, GET_PROCESS_LIST) with self.execute(query) as response: response.check_return_code() result: 'List[Process]' = [] process_count = response.number() lines_per_process = response.number() if not process_count or not lines_per_process: return result for _ in range(process_count): process = Process() process.number = response.ansi() process.ip_address = response.ansi() process.name = response.ansi() process.client_id = response.ansi() process.workstation = response.ansi() process.started = response.ansi() process.last_command = response.ansi() process.command_number = response.ansi() process.process_id = response.ansi() process.state = response.ansi() result.append(process) return result
def update_user_list(self, users: 'List[UserInfo]') -> bool: """ Обновление списка пользователей на сервере. :param users: Список пользователей :return: Признак успешности операции. """ if not self.check_connection(): return False assert isinstance(users, list) and users query = ClientQuery(self, SET_USER_LIST) for user in users: query.ansi(user.encode()) self.execute_forget(query) return True
def _fulltext_search_begin( self, search: SearchParameters, fulltext: TextParameters, ) -> ClientQuery: query = ClientQuery(self, FULL_TEXT_SEARCH) search.encode(query, self) fulltext.encode(query) return query
def update_ini_file(self, lines: 'List[str]') -> bool: """ Обновление строк серверного INI-файла. :param lines: Измененные строки. :return: Признак успешности операции. """ if not self.check_connection(): return False if not lines: return True query = ClientQuery(self, UPDATE_INI_FILE) for line in lines: query.ansi(line) self.execute_forget(query) return True
def write_text_file(self, *specification: FileSpecification) -> bool: """ Сохранение текстового файла на сервере. :param specification: Спецификация (включая текст для сохранения). :return: Признак успешности операции. """ if not self.check_connection(): return False query = ClientQuery(self, READ_DOCUMENT) is_ok = False for spec in specification: assert isinstance(spec, FileSpecification) query.ansi(str(spec)) is_ok = True if not is_ok: return False return self._execute_with_bool_result(query)
async def restart_server_async(self) -> bool: """ Асинхронный перезапуск сервера (без утери подключенных клиентов). :return: Признак успешности операции. """ if not self.check_connection(): return False query = ClientQuery(self, RESTART_SERVER) response = await self.execute_async(query) response.close() return True
def write_records(self, records: 'List[Record]') -> bool: """ Сохранение нескольких записей на сервере. Записи могут принадлежать разным базам. :param records: Записи для сохранения. :return: Результат. """ if not self.check_connection(): return False if not records: return True if len(records) == 1: return bool(self.write_record(records[0])) query = ClientQuery(self, "6") query.add(0).add(1) for record in records: database = record.database or self.database line = database + IRBIS_DELIMITER + \ IRBIS_DELIMITER.join(record.encode()) query.utf(line) with self.execute(query) as response: response.check_return_code() return True
async def nop_async(self) -> bool: """ Асинхронная пустая операция. :return: Признак успешности операции. """ if not self.check_connection(): return False query = ClientQuery(self, NOP) response = await self.execute_async(query) response.close() return True
async def connect_async(self) -> IniFile: """ Асинхронное подключение к серверу ИРБИС64. :return: INI-файл """ if self.connected: return self.ini_file while True: self.query_id = 0 self.client_id = random.randint(100000, 999999) query = ClientQuery(self, REGISTER_CLIENT) query.ansi(self.username).ansi(self.password) response = await self.execute_async(query) if response.get_return_code() == -3337: response.close() continue result = self._connect(response) response.close() return result
def delete_database(self, database: 'Optional[str]' = None) -> bool: """ Удаление базы данных. :param database: Имя удаляемой базы. :return: Признак успешности операции. """ if not self.check_connection(): return False database = self._get_database(database) query = ClientQuery(self, DELETE_DATABASE).ansi(database) return self._execute_with_bool_result(query)
def create_dictionary(self, database: 'Optional[str]' = None) -> bool: """ Создание словаря в базе данных. :param database: Имя базы данных. :return: Признау успешности операции. """ if not self.check_connection(): return False database = self._get_database(database) query = ClientQuery(self, CREATE_DICTIONARY).ansi(database) return self._execute_with_bool_result(query)
def list_users(self) -> 'List[UserInfo]': """ Получение списка пользователей с сервера. :return: Список пользователей """ if not self.check_connection(): return [] query = ClientQuery(self, GET_USER_LIST) with self.execute(query) as response: if not response.check_return_code(): return [] result = UserInfo.parse(response) return result
def execute(self, query: ClientQuery) -> ServerResponse: """ Выполнение произвольного запроса к серверу. :param query: Запрос :return: Ответ сервера (не забыть закрыть!) """ self.last_error = 0 sock = socket.socket() sock.connect((self.host, self.port)) packet = query.encode() sock.send(packet) result = ServerResponse(self) result.read_data(sock) result.initial_parse() return result
def get_server_stat(self) -> ServerStat: """ Получение статистики с сервера. :return: Полученная статистика """ if not self.check_connection(): return ServerStat() query = ClientQuery(self, GET_SERVER_STAT) with self.execute(query) as response: result = ServerStat() if not response.check_return_code(): return result result.parse(response) return result
def get_server_version(self) -> ServerVersion: """ Получение версии сервера. :return: Версия сервера """ if not self.check_connection(): return ServerVersion() query = ClientQuery(self, SERVER_INFO) with self.execute(query) as response: result = ServerVersion() if not response.check_return_code(): return result lines = response.ansi_remaining_lines() result.parse(lines) if not self.server_version: self.server_version = result.version return result
async def execute_async(self, query: ClientQuery) -> ServerResponse: """ Асинхронное исполнение запроса. ВНИМАНИЕ: сначала должна быть выполнена инициализация init_async()! :param query: Запрос. :return: Ответ сервера. """ self.last_error = 0 reader, writer = await asyncio.open_connection(self.host, self.port, loop=irbis_event_loop) packet = query.encode() writer.write(packet) result = ServerResponse(self) await result.read_data_async(reader) result.initial_parse() writer.close() return result
def read_text_stream( self, specification: 'Union[FileSpecification, str]', ) -> ServerResponse: """ Получение текстового файла с сервера в виде потока. :param specification: Спецификация или имя файла (если он находится в папке текущей базы данных). :return: ServerResponse, из которого можно считывать строки """ if isinstance(specification, str): specification = self.near_master(specification) assert isinstance(specification, FileSpecification) query = ClientQuery(self, READ_DOCUMENT).ansi(str(specification)) result = self.execute(query) return result
def get_database_info(self, database: 'Optional[str]' = None) \ -> DatabaseInfo: """ Получение информации о базе данных. :param database: Имя базы :return: Информация о базе """ if not self.check_connection(): return DatabaseInfo() database = self._get_database(database) query = ClientQuery(self, RECORD_LIST).ansi(database) with self.execute(query) as response: result = DatabaseInfo() if not response.check_return_code(): return result result.parse(response) result.name = database return result
async def read_text_file_async( self, specification: 'Union[FileSpecification, str]', ) -> str: """ Асинхронное получение содержимого текстового файла с сервера. :param specification: Спецификация или имя файла (если он находится в папке текущей базы данных). :return: Текст файла или пустая строка, если файл не найден """ if not self.check_connection(): return '' if isinstance(specification, str): specification = self.near_master(specification) query = ClientQuery(self, READ_DOCUMENT).ansi(str(specification)) response = await self.execute_async(query) result = response.ansi_remaining_text() result = irbis_to_dos(result) response.close() return result
def read_ini_file(self, specification: 'Union[FileSpecification, str]') \ -> IniFile: """ Чтение INI-файла с сервера. :param specification: Спецификация :return: INI-файл """ if not self.check_connection(): return IniFile() if isinstance(specification, str): specification = self.near_master(specification) assert isinstance(specification, FileSpecification) query = ClientQuery(self, READ_DOCUMENT).ansi(str(specification)) with self.execute(query) as response: result = IniFile() text = irbis_to_lines(response.ansi_remaining_text()) result.parse(text) return result
def read_binary_file( self, specification: 'Union[FileSpecification, str]', ) -> 'Optional[bytearray]': """ Чтение двоичного файла с сервера. :param specification: Спецификация файла. :return: Массив байт или None. """ if not self.check_connection(): return None if isinstance(specification, str): specification = self.near_master(specification) assert isinstance(specification, FileSpecification) specification.binary = True query = ClientQuery(self, READ_DOCUMENT).ansi(str(specification)) with self.execute(query) as response: result = response.get_binary_file() return result