Вложенный модуль box.session
Вложенный модуль box.session
позволяет делать запросы состояния сессии, вносить записи во временную Lua-таблицу по отдельной сессии, отправлять экстренные сообщения и настраивать триггеры, которые сработают в начале или окончании сессии.
Сессия – это объект, связанный с каждым подключением клиента.
Ниже приведен перечень всех функций и элементов модуля box.session
.
Имя | Использование |
---|---|
box.session.id() | Получение идентификатора текущей сессии |
box.session.exists() | Проверка наличия сессии |
box.session.peer() | Получение адреса хоста и порта подключенного узла |
box.session.sync() | Получение целочисленной константы sync |
box.session.user() | Получение имени текущего пользователя |
box.session.type() | Получение типа соединения или повода к действию |
box.session.su() | Изменение текущего пользователя |
box.session.uid() | Получение идентификатора текущего пользователя |
box.session.euid() | Получение идентификатора текущего действующего пользователя |
box.session.storage | Таблица с именами и значениями по сессии |
box.session.on_connect() | Определение триггера для подключения |
box.session.on_disconnect() | Определение триггера для отключения |
box.session.on_auth() | Определение триггера для аутентификации |
box.session.push() | Отправка внеполосного сообщения |
-
box.session.
id
() возвращается: уникальный идентификатор (ID) для текущей сессии. Результатом может быть 0 или -1, что означает, что сессии нет. тип возвращаемого значения: число
-
box.session.
exists
(id) возвращается: true if the session exists, false if the session does not exist. тип возвращаемого значения: boolean
-
box.session.
peer
(id) Данная функция сработает только в том случае, если есть подключенная программа, то есть если было выполнено подключение к отдельному экземпляру Tarantool’а.
возвращается: Адрес хоста и порт подключенного узла, например «127.0.0.1:55457». Если существует сессия, но отсутствует подключение к отдельному экземпляру, вернется null. Команда выполняется на экземпляре сервера, поэтому «локальное имя» – это хост и порт экземпляра сервера, а «имя узла» – это хост и порт клиента. тип возвращаемого значения: string (строка) Возможные ошибки: „session.peer(): сессия отсутствует“
-
box.session.
sync
() возвращается: значение целочисленной константы sync
, используемой в бинарном протоколе. Это значение будет недействительным после отключения сессии.тип возвращаемого значения: число This function is local for the request, i.e. not global for the session. If the connection behind the session is multiplexed, this function can be safely used inside the request processor.
-
box.session.
user
() возвращается: имя текущего пользователя тип возвращаемого значения: string (строка)
-
box.session.
type
() возвращается: тип соединения или повод к действию. тип возвращаемого значения: string (строка) Возможные возвращаемые значения:
- „binary“ (бинарное), если подключение было выполнено по бинарному протоколу, например, к объекту с помощью box.cfg{listen=…};
- „console“ (консоль), если подключение было выполнено по административной консоли, например, к объекту с помощью console.listen;
- „repl“ (репликация), если подключение было выполнено напрямую, например, при использовании Tarantool’а в качестве клиента;
- „applier“ (наложение), если действие происходит по причине репликации, независимо от типа подключения;
- „background“ (в фоне), если действие происходит в фоновом файбере, независимо от того, был ли Tarantool запущен в фоновом режиме.
box.session.type()
используется для триггера при замене on_replace() на реплике – значение будет „applier“ только в том случае, если триггер был активирован по причине запроса, выполненного на мастере.
-
box.session.
su
(user-name[, function-to-execute]) Изменение текущего пользователя Tarantool’а – аналогично Unix-команде
su
.Или, если указана выполняемая функция (function-to-execute), временное изменение текущего пользователя Tarantool’а во время выполнения функции – аналогично Unix-команде
sudo
.Параметры: - user-name (string) – целевое имя пользователя
- function-to-execute – имя функции или определение функции. Дополнительные параметры могут передаваться в
box.session.su
, они будут интерпретироваться как параметры выполняемой функции.
Пример
tarantool> function f(a) return box.session.user() .. a end --- ... tarantool> box.session.su('guest', f, '-xxx') --- - guest-xxx ... tarantool> box.session.su('guest',function(...) return ... end,1,2) --- - 1 - 2 ...
-
box.session.
uid
() возвращается: ID текущего пользователя. тип возвращаемого значения: число У каждого пользователя есть уникальное имя (узнать с помощью box.session.user()) и уникальный идентификатор (узнать с помощью
box.session.uid()
). Значения хранятся вместе в спейсе_user
.
-
box.session.
euid
() возвращается: рабочий ID текущего пользователя. Аналогично box.session.uid(), за исключением двух случаев:
- Первый случай: если вызов
box.session.euid()
выполняется в рамках функции, вызываемой по box.session.su(user-name, function-to-execute) – в таком случаеbox.session.euid()
вернет измененный идентификатор пользователя (пользователь, который указан в параметреuser-name
функцииsu
), ноbox.session.uid()
вернет идентификатор оригинального пользователя (пользователя, который вызывает функциюsu
). - Второй случай: если вызов
box.session.euid()
выполняется в рамках функции по box.schema.func.create(function-name, {setuid= true}), и используется бинарный протокол – в таком случаеbox.session.euid()
вернет идентификатор пользователя, который создал функцию «function-name», аbox.session.uid()
вернет идентификатор пользователя, который вызывает эту функцию «function-name».
тип возвращаемого значения: число Пример
tarantool> box.session.su('admin') --- ... tarantool> box.session.uid(), box.session.euid() --- - 1 - 1 ... tarantool> function f() return {box.session.uid(),box.session.euid()} end --- ... tarantool> box.session.su('guest', f) --- - - 1 - 0 ...
- Первый случай: если вызов
-
box.session.
storage
Lua-таблица с произвольными неупорядоченными именами и значениями по сессии, которая хранится до конца сессии. Например, эту таблицу можно использовать для хранения текущих задач при работе с очередями сообщений в Tarantool’е.
Пример
tarantool> box.session.peer(box.session.id()) --- - 127.0.0.1:45129 ... tarantool> box.session.storage.random_memorandum = "Don't forget the eggs" --- ... tarantool> box.session.storage.radius_of_mars = 3396 --- ... tarantool> m = '' --- ... tarantool> for k, v in pairs(box.session.storage) do > m = m .. k .. '='.. v .. ' ' > end --- ... tarantool> m --- - 'radius_of_mars=3396 random_memorandum=Don't forget the eggs. ' ...
-
box.session.
on_connect
([trigger-function[, old-trigger-function]]) Определение исполняемого триггера во время создания новой сессии при подключению по консоли console.connect. Функция с триггером будет первой исполняемой функцией после создания сессии. Если триггер не выполняется и выдает ошибку, эта ошибка отправляется на клиент, и подключение разрывается.
Параметры: - trigger-function (function) – функция, в которой будет триггер
- old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращается: nil или указатель функции
Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.
Если не указан ни один параметр, ответом будет список существующих функций с триггером.
Подробная информация о характеристиках триггера находится в разделе Триггеры.
Пример
tarantool> function f () > x = x + 1 > end tarantool> box.session.on_connect(f)
Предупреждение
Если триггер всегда приводит к ошибке, подключение к серверу для его переустановки может стать невозможным.
-
box.session.
on_disconnect
([trigger-function[, old-trigger-function]]) Определение исполняемого триггера после отключения клиента. Если функция с триггером вызывает ошибку, то ошибка записывается в журнал, в противном случае записей не будет. Триггер вызывается во время сессии клиента и может получить доступ к свойствам сессии, как box.session.id().
Начиная с версии 1.10, функция с триггером вызывается сразу же после прерывания сессии, даже если сделанные запросы не были выполнены.
Параметры: - trigger-function (function) – функция, в которой будет триггер
- old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращается: nil или указатель функции
Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.
Если не указан ни один параметр, ответом будет список существующих функций с триггером.
Подробная информация о характеристиках триггера находится в разделе Триггеры.
Пример №1
tarantool> function f () > x = x + 1 > end tarantool> box.session.on_disconnect(f)
Пример №2
После следующей серии запросов экземпляр Tarantool’а запишет сообщение с помощью модуля log при подключении или отключении любого пользователя.
function log_connect () local log = require('log') local m = 'Connection. user=' .. box.session.user() .. ' id=' .. box.session.id() log.info(m) end function log_disconnect () local log = require('log') local m = 'Disconnection. user=' .. box.session.user() .. ' id=' .. box.session.id() log.info(m) end box.session.on_connect(log_connect) box.session.on_disconnect(log_disconnect)
Вот что может быть записано в файл журнала при обычной установке:
2014-12-15 13:21:34.444 [11360] main/103/iproto I> Connection. user=guest id=3 2014-12-15 13:22:19.289 [11360] main/103/iproto I> Disconnection. user=guest id=3
-
box.session.
on_auth
([trigger-function[, old-trigger-function]]) Определение триггера, используемого во время аутентификации.
Вызов функции
on_auth
с триггером происходит в следующих обстоятельствах:- Функция console.connect включает в себя проверку аутентификации всех пользователей, кроме „guest“. Вызов функции
on_auth
с триггером происходит после триггераon_connect
только в том случае, если подключение было успешным. - В бинарном протоколе есть отдельный пакет для аутентификации. В этом случае подключение и аутентификация считаются отдельными действиям.
В отличие от других типов триггеров, вызов функций с триггером
on_auth
происходит до события. Таким образом, функция с таким триггером, какfunction auth_function () v = box.session.user(); end
, определитv
как «guest», то есть имя пользователя до проведения аутентификации. Чтобы получить имя пользователя после проведения аутентификации, используйте специальный синтаксис:function auth_function (user_name) v = user_name; end
Если триггер не выполняется и выдает ошибку, эта ошибка отправляется на клиент, и подключение разрывается.
Параметры: - trigger-function (function) – функция, в которой будет триггер
- old-trigger-function (function) – существующая функция с триггером, которую заменит новая
возвращается: nil или указатель функции
Если указаны параметры (nil, old-trigger-function), старый триггер будет удален.
Если не указан ни один параметр, ответом будет список существующих функций с триггером.
Подробная информация о характеристиках триггера находится в разделе Триггеры.
Пример 1
tarantool> function f () > x = x + 1 > end tarantool> box.session.on_auth(f)
Пример 2
Более сложный пример с двумя экземплярами сервера.
Первый экземпляр сервера настроен на прослушивание по порту 3301; имя пользователя по умолчанию – „admin“. Есть три триггера
on_auth
:- В первом триггере есть функция без аргументов, которая только смотрит на
box.session.user()
. - Во втором триггере есть функция с аргументом
user_name
, которая может смотреть наbox.session.user()
иuser_name
. - В третьем триггере есть функция с аргументом
user_name
и аргументомstatus
, которая может смотреть наbox.session.user()
иuser_name
, и``status``.
Второй экземпляр сервера подключится по console.connect, а затем отобразит переменные, определенные функциями с триггером.
-- На первом экземпляре сервера, прослушивание на котором настроено на порт 3301 box.cfg{listen=3301} function function1() print('function 1, box.session.user()='..box.session.user()) end function function2(user_name) print('function 2, box.session.user()='..box.session.user()) print('function 2, user_name='..user_name) end function function3(user_name, status) print('function 3, box.session.user()='..box.session.user()) print('function 3, user_name='..user_name) if status == true then print('function 3, status = true, authorization succeeded') end end box.session.on_auth(function1) box.session.on_auth(function2) box.session.on_auth(function3) box.schema.user.passwd('admin')
-- На втором экземпляре сервера, который подключается по порту 3301 console = require('console') console.connect('admin:admin@localhost:3301')
Теперь результат выглядит следующим образом:
function 3, box.session.user()=guest function 3, user_name=admin function 3, status = true, authorization succeeded function 2, box.session.user()=guest function 2, user_name=admin function 1, box.session.user()=guest
- Функция console.connect включает в себя проверку аутентификации всех пользователей, кроме „guest“. Вызов функции
-
box.session.
push
(message[, sync]) Создание внеполосного сообщения. Под внеполосным мы понимаем дополнительное сообщение, которое дополняет то, что отправляется в сети по обычным каналам. Хотя
box.session.push()
можно вызвать в любое время, на практике эта функция используется в сетях, настроенных с помощью модуля net.box, и вызывается сервером (на «удаленной системе с базой данных», если использовать нашу терминологию для net.box), а у клиента есть возможность принимать такие сообщения.Функция возвращает ошибку, если сессия была прервана.
Параметры: - message (any-Lua-type) – что отправляется
- sync (int) – необязательный аргумент, который показывает информацию о сессии, полученную из предшествующего вызова box_session:sync(). Если не указать, по умолчанию используется текущее значение
box.session.sync()
.
тип возвращаемого значения: {nil, ошибка} или true:
- Если результатом будет ошибка, то вернется
nil
вместе с объектом ошибки. - Если результатом будет не ошибка, то вернется логическое значение
true
(правда). - Если возвращается
true
, сообщение отправлено в буфер сети в виде пакета с кодом IPROTO_CHUNK (0x80).
Единственная задача сервера – вызвать
box.session.push()
, поскольку нет автоматического механизма, который показал бы, что сообщение получено.Задача клиента заключается в том, чтобы проверять наличие таких сообщений после отправки чего-либо на сервер. Основные клиентские методы – conn:call, conn:eval, conn:select, conn:insert, conn:replace, conn:update, conn:upsert, delete – могут привести к отправке такого сообщения сервером.
Ситуация 1: когда клиент делает синхронный вызов со значением параметра
{async=false}
по умолчанию. Есть два необязательных дополнительных параметра:on_push=function-name
иon_push_ctx=function-argument
. Когда клиент получает внеполосное сообщение в сессии, он вызывает «имя-функции(аргумент-функции)». Например, с такими значениями параметров:{on_push=table.insert, on_push_ctx=messages}
– клиент произведет вставку полученных данных в таблицу под названием „messages“.Ситуация 2: когда клиент делает асинхронный вызов с измененным значением параметра
{async=true}
. Здесь не разрешеныon_push
иon_push_ctx
, но сообщения можно увидеть путем вызоваpairs()
в цикле.Осложненная ситуация 2:
pairs()
зависит от времени ожидания. Таким образом, есть необязательный аргумент – время ожидания для итерации. Если время ожидания истечет до получения нового сообщения или окончательного ответа, вернется ошибка. Чтобы проверить наличие ошибки, можно использовать первый параметр в цикле (если цикл начинается с «for i, message in future:pairs()», то первым параметром в цикле будет i). Если это будетbox.NULL
, то второй параметр (в нашем примере «message») – это объект ошибки.Пример
-- Создайте две оболочки. В оболочке №1 настройте сервер, а -- в нем функцию, которая содержит box.session.push: box.cfg{listen=3301} box.schema.user.grant('guest','read,write,execute','universe') x = 0 fiber = require('fiber') function server_function() x=x+1; fiber.sleep(1); box.session.push(x); end -- В оболочке №2 подключитесь к серверу в качестве клиента, который -- поддерживает Lua (как второй Tarantool-сервер, работающий -- в качестве клиента), и создайте таблицу, в которую мы будем получать сообщения: net_box = require('net.box') conn = net_box.connect(3301) messages_from_server = {} -- В оболочке №2 удаленно вызовите функцию и получите -- СИНХРОННОЕ внеполосное сообщение: conn:call('server_function', {}, {is_async = false, on_push = table.insert, on_push_ctx = messages_from_server}) messages_from_server -- Через секунду, во время которой происходит запрос fiber.sleep() -- в server_function, результат в таблице -- messages_from_server будет следующим: 1. Проверим: -- tarantool> messages_from_server -- --- -- - - 1 -- ... -- Хорошо. Это означает, что box.session.push(x) сработала, -- поскольку мы знаем, что x был 1. -- В оболочке №2 удаленно вызовите ту же самую функцию -- для получения АСИНХРОННОГО внеполосного сообщения. При этом мы не можем -- использовать параметры on_push и on_push_ctx, но можем использовать pairs(): future = conn:call('server_function', {}, {is_async = true}) messages = {} keys = {} for i, message in future:pairs() do table.insert(messages, message) table.insert(keys, i) end messages future:wait_result(1000) for i, message in future:pairs() do table.insert(messages, message) table.insert(keys, i) end messages -- Задержки нет, поскольку conn:call не ждет -- окончания вызова функции server_function. После первой итерации -- цикла pairs(), видим, что таблица пуста. Это выглядит так: -- tarantool> messages -- --- -- - - 2 -- - [] -- ... -- Это нормально, поскольку сервер еще не вызвал -- box.session.push(). При второй итерации -- цикла pairs(), видим значение x во время -- второго вызова box.session.push(). Так: -- tarantool> messages -- --- -- - - 2 -- - &0 [] -- - 2 -- - *0 -- ... -- Хорошо. Это означает, что сообщение было асинхронным, и -- box.session.push() выполнила свою задачу.