Версия:

Вложенный модуль box.session

Вложенный модуль box.session

Общие сведения

The box.session submodule allows querying the session state, writing to a session-specific temporary Lua table, or sending out-of-band messages, or setting up triggers which will fire when a session starts or ends.

A session is an object associated with each client connection.

Индекс

Ниже приведен перечень всех функций и элементов модуля 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() Send an out-of-band message
box.session.id()
возвращается:уникальный идентификатор (ID) для текущей сессии. Результатом может быть 0, что означает, что сессии нет.
тип возвращаемого значения:
 число
box.session.exists(id)
возвращается:1, если сессия есть; 0, если сессии нет.
тип возвращаемого значения:
 число
box.session.peer(id)

Данная функция сработает только в том случае, если есть подключенная программа, то есть если было выполнено подключение к отдельному экземпляру Tarantool’а.

возвращается:Адрес хоста и порт подключенного узла, например «127.0.0.1:55457». Если существует сессия, но отсутствует подключение к отдельному экземпляру, вернется null. Команда выполняется на экземпляре сервера, поэтому «локальное имя» – это хост и порт экземпляра сервера, а «имя узла» – это хост и порт клиента.
тип возвращаемого значения:
 string (строка)

Возможные ошибки: „session.peer(): сессия отсутствует“

box.session.sync()
возвращается:the value of the sync integer constant used in the binary protocol.
тип возвращаемого значения:
 число
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().

Параметры:
  • 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 с триггером происходит в следующих обстоятельствах:

  1. Функция console.connect включает в себя проверку аутентификации всех пользователей, кроме „guest“. Вызов функции on_auth с триггером происходит после триггера on_connect только в том случае, если подключение было успешным.
  2. В бинарном протоколе есть отдельный пакет для аутентификации. В этом случае подключение и аутентификация считаются отдельными действиям.

В отличие от других типов триггеров, вызов функций с триггером 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
box.session.push(message[, sync])

Generate an out-of-band message. By «out-of-band» we mean an extra message which supplements what is passed in a network via the usual channels. Although box.session.push() can be called at any time, in practice it is used with networks that are set up with module net.box, and it is invoked by the server (on the «remote database system» to use our terminology for net.box), and the client has options for getting such messages.

Параметры:
  • message (string-or-number) – what to send
  • sync (int) – an optional argument to indicate what the session is, as taken from an earlier call to box_session:sync(). If it is omitted, the default is the current box.session.sync() value.
тип возвращаемого значения:
 

{nil, error} or true:

  • If the result is an error, then the first part of the return is nil and the second part is the error object.
  • If the result is not an error, then the return is the boolean value true.
  • When the return is true, the message has gone to the network buffer as a packet with the code IPROTO_CHUNK (0x80).

The server’s sole job is to call box.session.push(), there is no automatic mechanism for showing that the message was received.

The client’s job is to check for such messages after it sends something to the server. The major client methods – conn:call, conn:eval, conn:select, conn:insert, conn:replace, conn:update, conn:upsert, delete – may cause the server to send a message.

Situation 1: when the client calls synchronously with the default {async=false} option. There are two optional additional options: on_push=function-name, and on_push_ctx=function-argument. When the client receives an out-of-band message for the session, it invokes «function-name(function-argument)». For example, with options {on_push=table.insert, on_push_ctx=messages}, the client will insert whatever it receives into a table named „messages“.

Situation 2: when the client calls asynchronously with the non-default {async=true} option. Here on_push and on_push_ctx are not allowed, but the messages can be seen by calling pairs() in a loop.

Situation 2 complication: pairs() is subject to timeout. So there is an optional argument = timeout per iteration. If timeout occurs before there is a new message or a final response, there is an error return. To check for an error one can use the first loop parameter (if the loop starts with «for i, message in future:pairs()» then the first loop parameter is i). If it is box.NULL then the second parameter (in our example, «message») is the error object.

Пример

-- Make two shells. On Shell#1 set up a "server", and
-- in it have a function that includes 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

-- On Shell#2 connect to this server as a "client" that
-- can handle Lua (such as another Tarantool server operating
-- as a client), and initialize a table where we'll get messages:
net_box = require('net.box')
conn = net_box.connect(3301)
messages_from_server = {}

-- On Shell#2 remotely call the server function and receive
-- a SYNCHRONOUS out-of-band message:
conn:call('server_function', {},
          {is_async = false,
           on_push = table.insert,
           on_push_ctx = messages_from_server})
messages_from_server
-- After a 1-second pause that is caused by the fiber.sleep()
-- request inside server_function, the result in the
--  messages_from_server table will be: 1. Like this:
-- tarantool> messages_from_server
-- ---
-- - - 1
-- ...
-- Good. That shows that box.session.push(x) worked,
-- because we know that x was 1.

-- On Shell#2 remotely call the same server function and
-- get an ASYNCHRONOUS out-of-band message. For this we cannot
-- use on_push and on_push_ctx options, but we can use 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
-- There is no pause because conn:call does not wait for
-- server_function to finish. The first time that we go through
-- the pairs() loop, we see the messages table is empty. Like this:
-- tarantool> messages
-- ---
-- - - 2
--   - []
-- ...
-- That is okay because the server hasn't yet called
-- box.session.push(). The second time that we go through
-- the pairs() loop, we see the value of x at the time of
-- the second call to box.session.push(). Like this:
-- tarantool> messages
-- ---
-- - - 2
--   - &0 []
--   - 2
--   - *0
-- ...
-- Good. That shows that the message was asynchronous, and
-- that box.session.push() did its job.