Класс Connection
Класс Connection
- «рабочая лошадка». Он осуществляет связь с сервером и всю необходимую перепаковку данных из клиентского представления в сетевое.
Экземпляр клиента создается конструктором:
import irbis
client = irbis.Connection()
При создании клиента можно указать (некоторые) настройки:
import irbis
client = irbis.Connection(host='irbis.rsl.ru', port=5555, username='ninja')
Можно задать те же настройки с помощью полей host, port и т. д.:
import irbis
client = irbis.Connection()
client.host = 'irbis.rsl.ru'
client.port = 5555
Поле |
Тип |
Назначение |
Значение по умолчанию |
---|---|---|---|
host |
str |
Адрес сервера |
„127.0.0.1“ |
port |
int |
Порт |
6666 |
username |
str |
Имя (логин) пользователя |
None |
password |
str |
Пароль пользователя |
None |
database |
str |
Имя базы данных |
„IBIS“ |
workstation |
str |
Тип АРМа (см. таблицу ниже) |
„C“ |
Типы АРМов
Обозначение |
Тип |
Константа |
---|---|---|
„R“ |
Читатель |
READER |
„C“ |
Каталогизатор |
CATALOGER |
„M“ |
Комплектатор |
ACQUISITIONS |
„B“ |
Книговыдача |
CIRCULATION |
„K“ |
Книгообеспеченность |
PROVISION |
„A“ |
Администратор |
ADMINISTRATOR |
Обратите внимание, что адрес сервера задается строкой, так что может принимать как значения вроде 192.168.1.1
, так и irbis.yourlib.com
.
Тип рабочей станции лучше задавать константой:
import irbis
client = irbis.Connection()
client.host = '8.8.8.8'
client.workstation = irbis.ADMINISTRATOR
Если какой-либо из вышеперечисленных параметров не задан явно, используется значение по умолчанию.
Имейте в виду, что логин и пароль пользователя не имеют значения по умолчанию, поэтому должны быть заданы явно.
Подключение к серверу и отключение от него
Только что созданный клиент еще не подключен к серверу. Подключаться необходимо явно с помощью метода connect
, при этом можно указать параметры подключения:
import irbis
client = irbis.Connection()
client.connect('192.168.1.2', 6666, 'librarian', 'secret')
if not client:
print('Подключиться не удалось')
Отключаться от сервера можно двумя способами: во-первых, с помощью метода disconnect
:
client.disconnect()
во-вторых, с помощью контекста, задаваемого блоком with
:
import irbis
with irbis.Connection(host='192.168.1.3') as client:
client.connect(username='itsme', password='secret')
if not client:
print('Подключиться не удалось')
exit(1)
# Выполняем некие действия.
# По выходу из блока отключение от сервера произойдет автоматически.
При подключении клиент получает с сервера INI-файл с настройками, которые могут понадобиться в процессе работы:
import irbis
client = irbis.Connection()
ini = client.connect()
format_menu_name = ini.get_value('Main', 'FmtMnu', 'FMT31.MNU')
Полученный с сервера INI-файл также хранится в поле ini_file
.
Повторная попытка подключения с помощью того же экземпляра Connection
игнорируется. При необходимости можно создать другой экземпляр и подключиться с его помощью (если позволяют клиентские лицензии). Аналогично игнорируются повторные попытки отключения от сервера.
Проверить статус «клиент подключен или нет» можно с помощью преобразования подключения к типу bool
:
import irbis
client = irbis.Connection()
# спустя 300 строк кода
if not client:
# В настоящий момент мы не подключены
return
Вместо индивидуального задания каждого из полей host
, port
, username
, password
и database
предпочтительнее использовать метод parse_connection_string
:
import irbis
client = irbis.Connection()
client.parse_connection_string('host=192.168.1.4;port=5555;username=itsme;password=secret;db=RDR;')
client.connect()
# выполняем какие-нибудь действия
client.disconnect()
Подключенный клиент может сформировать строку подключения (с помощью метода to_connection_string
), которую можно использовать для другого подключения:
import irbis
client1 = irbis.Connection()
client1.connect('host', 6666, 'librarian', 'secret')
# выполняем какие-нибудь действия
connection_string = client1.to_connection_string()
client1.disconnect()
client2 = irbis.Connection()
client2.parse_connection_string(connection_string)
client2.connect()
# выполняем какие-нибудь действия
client2.disconnect()
Многопоточность
Клиент написан в наивном однопоточном стиле, поэтому не поддерживает одновременный вызов методов из разных потоков.
Для одновременной отсылки на сервер нескольких команд необходимо создать соответствующее количество экземпляров подключений (если подобное позволяет лицензия сервера).
Подтверждение подключения
irbis
не посылает самостоятельно на сервер подтверждений того, что клиент все еще подключен. Этим должно заниматься приложение, например, по таймеру.
Подтверждение посылается серверу методом nop
:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
client.nop()
client.disconnect()
Чтение записей с сервера
Для индивидуального чтения записи с сервера применяется метод read_record
.
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
mfn = 123
record = client.read_record(mfn)
print(record.status)
client.disconnect()
Для группового чтения записей с сервера применяется метод read_records
.
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
mfns = [12, 34, 56]
records = client.read_records(mfns)
for record in records:
print(record.status)
client.disconnect()
Методы для работы записями в клиентском представлении (доступ к полям/подполям, добавление/удаление полей и т. д.) см. в следующей главе.
Сохранение записи на сервере
Вновь созданную либо модифицированную запись можно сохранить на сервере с помощью метода write_record
. Сначала покажем, как выполняется модификация записи:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
mfn = 123
record = client.read_record(mfn)
# Добавляем в запись поле 300 (общее примечание)
record.add(300, 'Примечание к записи')
# Сохраняем запись обратно на сервер
client.write_record(record)
client.disconnect()
Теперь попробуем создать запись «с нуля» и сохранить её в базе данных:
import irbis
SF = irbis.SubField # для краткости
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Создаём запись и наполняем её полями
record = irbis.Record()
record.add(200, SF('a', 'Заглавие'))
record.add(700, SF('a', 'Фамилия автора'))
# Отправляем запись на сервер
# Запись попадёт в текущую базу данных
client.write_record(record)
client.disconnect()
Удаление записей
Удаление записи заключается в установке её статуса LOGICALLY_DELETED
. Для этого применяется метод delete_record
, принимающий MFN записи:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
mfn = 123 # MFN записи, подлежащей удалению
client.delete_record(mfn)
client.disconnect()
После удаления запись становится логически удалённой, т. е. физически она присутствует в файле документов и может быть считана клиентом, однако исключается из поиска. Логически удалённую запись в любой момент можно восстановить с помощью метода undelete_record
, также принимающего MFN записи.
Администратор может провести на сервере так называемую реорганизацию файла документов, в процессе которой логически удалённые записи будут исключены из мастер-файла (однако, за ними сохранится MFN). Такие записи не могут быть прочитаны и/или восстановлены клиентом.
Поиск записей
Поиск записей в ИРБИС осуществляется двумя способами:
Так называемый «прямой поиск», выполняемый по автоматически поддерживаемому поисковому индексу (словарю). Используется специальный синтаксис, описанный на странице http://sntnarciss.ru/irbis/spravka/pril01701001000.htm
Так называемый «последовательный поиск», заключающийся в последовательном переборе записей. Для него используется другой синтаксис, описанный на странице http://sntnarciss.ru/irbis/spravka/pril01701002000.htm.
Прямой поиск
Обратите внимание, что при прямом поиске мы заключаем искомые термины в дополнительные двойные кавычки, это требование сервера ИРБИС64 (ведь термины могут включать в себя пробелы и специальные символы, и без кавычек сервер не сможет определить конец одного термина и начало другого).
Вот как выглядит правильно сформулированное поисковое выражение:
search_expression = '"A=ПУШКИН$" * ("T=СКАЗКИ$" + "T=ПОВЕСТИ$")'
Количество найденных записей по данному запросу:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Находим книги, автором которых является Пушкин
count = client.search_count('"A=ПУШКИН$"')
print(f"Всего книг Пушкина в фонде: {count}")
client.disconnect()
Имейте в виду, что сервер ИРБИС64 возвращает записи в произвольном порядке! Чаще всего этот порядок совпадает с порядком, в котором записи были введены в базу данных. Поэтому сортировать записи должен сам клиент.
Обычный поиск с помощью метода search
выдаёт не более 32 тыс. найденных записей (это ограничение сервера ИРБИС64):
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Получаем MFN книг, автором которых является Пушкин
found = client.search('"A=ПУШКИН$"')
# Распечатываем список найденных MFN
print('Найдены MFN:', ', '.join(found))
client.disconnect()
Метод search_all
выдаёт все найденные записи, в т. ч. если их много больше 32 тыс. Осторожно! Этот метод может занять много времени и ресурсов как сервера, так и клиента!
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Получаем MFN книг, у которых есть хотя бы один автор
found = client.search_all('"A=$"')
# Распечатываем список найденных MFN
print('Найдены MFN:', ', '.join(found))
client.disconnect()
Можно объединить поиск с одновременным считыванием записей, применив метод search_read
. Осторожно! Этот метод может занять много времени и ресурсов как сервера, так и клиента! Устанавливайте разумное значение параметра limit
при вызове этого метода.
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Считываем первые 5 найденных записей для книг,
# автором которых является Пушкин
found = client.search_read('"A=ПУШКИН$"', 5)
# Распечатываем заглавия найденных книг:
for record in found:
print(record.fm(200, 'a'))
client.disconnect()
Поиск с одновременным расформатированием записей осуществляется методм search_format
:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Расформатируем первые 5 найденных записей для книг,
# автором которых является Пушкин
found = client.search_format('"A=ПУШКИН$"', '@brief', 5)
# Распечатываем результаты форматирования:
for line in found:
print(line)
client.disconnect()
Последовательный поиск
Последовательный поиск можно выполнить при помощи метода search_ex
, принимающий в себя спецификацию поискового запроса SearchParameters
. Часто последовательный поиск проводят по результатам предварительного прямого поиска. В терминах SearchParameters
это означает задание значения поля sequential
(выражение для последовательного поиска) вместе (согласованно) со значением поля expression
(выражение для прямого поиска).
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
params = irbis.SearchParameters()
params.database = 'IBIS' # По какой базе ищем
params.expression = '"A=ПУШКИН$"' # Прмямой поисй (по словарю)
params.number = 10 # Выдать не больше 10 записей
params.format = '@brief' # Форматирование найденных записей
# Последовательнсый поиск среди отобранных по словарю записей
params.sequential = "if v200^a:'Сказки' then '1' else '0' fi"
found = client.search_ex(params)
for line in found:
record = client.read_record(line.mfn)
print(record.fm(200, 'a'))
# Получаем расформатированную запись
print(line.description)
Работа с текстовыми файлами на сервере
Сначала необходимо упомянуть об используемой сервером ИРБИС64 спецификации имён файлов. Эта спецификация выглядит так:
Расположение . База . ИмяФайла
где расположение
- число, означающее место, где сервер должен искать файл:
0 – общесистемный путь (директория, в которую установлен сервер ИРБИС64), чаще всего
C:\IRBIS64
.1 – путь размещения сведений о базах данных сервера ИРБИС64, чаще всего
C:\IRBIS64\DATAI
.2 – путь на мастер-файл базы данных. Для базы данных IBIS чаще всего выглядит так:
C:\IRBIS64\DATAI\IBIS
.3 – путь на словарь базы данных. Чаще всего совпадает с предыдущим путём.
10 – путь на параметрию базы данных. Чаще всего совпадает с предыдущим путём.
Для расположений 0
и 1
имя базы данных указывать не нужно, т. к. оно не имеет смысла. Такие пути выглядят так:
0..RC.MNU
- меню с римскими цифрами, хранится рядом с сервером ИРБИС64.1..dbnam2.mnu
- меню со списком баз данных, доступных АРМ «Каталогизатор», хранится в папкеDATAI
.
Для остальных расположений между двух точек указывают имя базы данных. Примеры:
2.IBIS.brief.pft
- формат краткого библиографического описания для базы данныхIBIS
.2.RDR.email.pft
- формат электронной почты для базы данныхRDR
.2.CMPL.KP.MNU
- меню с каналами поступления для базы данныхCMPL
.
Для путей, больших или равных 2, сервер сначала ищет файл в директории, заданной в PAR-файле, и, если не находит там, то пытается найти файл с тем же именем в папке Deposit
.
Обратите внимание! Сервер ИРБИС64 под Windows игнорирует регистр символов в спецификации имён файлов!
Чаще всего клиенты считывают с сервера следующие текстовые файлы:
форматы (имеют расширение PFT) для формирования каталожных карточек и списков литературы,
меню (имеют расширение MNU),
иерархические меню (имеют расширение TRE),
INI-файлы со сценариями поиска,
рабочие листы ввода (имеют расширения WS и WSS).
Однако, ничего не мешает клиентам получать с сервера и любые другие текстовые и двоичные файлы, необходимые им для работы.
Текстовый файл можно получить с сервера с помощью метода read_text_file
:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Считываем формат краткого библиографического
# описания для базы IBIS
brief = client.read_text_file('2.IBIS.brief.pft')
print('BRIEF:', brief)
client.disconnect()
Обратите внимание! Если сервер не может найти указанный файл, либо не может получить доступ к этому файлу (недостаточно прав), он возвращает строку нулевой длины!
Для считывания с сервера меню, иерархических справочников и других специфических текстовых файлов имеются соответствующие методы, описанные в главе 4.
Сохранить текстовый файл на сервере можно с помощью метода write_text_file
. Имейте в виду, что текстовые файлы на сервере хранятся, как правило, в кодировке CP1251, так что все символы, не имеющие представления в данной кодировке, будут утеряны при сохранении.
Для получения с сервера двоичных файлов (например, изображений) используется метод read_binary_file
:
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Считываем GIF-файл с бегущим ирбисом,
# хранящийся рядом с сервером ИРБИС64
running = client.read_binary_file('0..irbis.gif')
# Сохраняем в локальный файл
with open('bars.gif', 'wb') as f:
f.write(running)
client.disconnect()
Получить список файлов на сервере можно с помощью метода list_files
. В него передаётся перечень (может состоять из одного файла) спецификаций файлов, которые нас интересуют. Разрешается использовать метасимволы „?“ и „*“, имеющие тот же смысл, что и в командной строке Windows. Метод возвращает массив имён (не спецификаций!) найденных файлов.
import irbis
client = irbis.Connection()
client.connect('host', 6666, 'librarian', 'secret')
# Получаем список форматных файлов для базы IBIS
formats = client.list_files('2.IBIS.')
# Распечатываем полученный список файлов:
print(formats)
client.disconnect()
Поддержка асинхронности
import irbis
async def do_async_stuff():
result = await connection.connect_async()
if not result:
print('Failed to connect')
return
print('Connected')
max_mfn = await connection.get_max_mfn_async()
print(f"Max MFN={max_mfn}")
text = await connection.format_record_async('@brief', 1)
print(text)
await connection.nop_async()
print('NOP')
record = await connection.read_record_async(1)
print(record)
text = await connection.read_text_file_async('dn.mnu')
print(text)
count = await connection.search_count_async('K=бетон')
print(f'Count={count}')
found = await connection.search_async('K=бетон')
print(found)
await connection.disconnect_async()
print('Disconnected')
#=============================================
connection = irbis.Connection()
connection.host = 'localhost'
connection.username = 'librarian'
connection.password = 'secret'
connection.database = 'IBIS'
irbis.init_async()
irbis.irbis_event_loop.run_until_complete(do_async_stuff())
irbis.close_async()