разработка информационных систем
Banner  
О нас О нас
Наши продукты Наши продукты
Clip CLIP
R2D2 R2D2
Статьи Статьи
Контакты Контакты
Карта
English English

Наши продукты

State Machine
Машина состояний web-сервера для создания сложных internet-приложений


Download (ftp://ftp.itk.ru/pub/sm)

Mailto: Paul Lasarev

1. Краткое описание.


State Machine (далее SM) была разработана для преодоления главного (на наш взгляд) неудобства при разработке достаточно сложных Web-приложений - отсутствия постоянного (хотя бы на время сеанса) пользовательского контекста. В результате:

  • либо становится невозможным создание программы в виде привычного программистам (и пользователям) дерева вызовов типа "вызов процедуры - возврат" (или, с точки зрения пользователя, например, "появление окна диалога - возврат");
  • либо приходится контекст выполнения в некотором виде "гонять" между формами (что просто ужасно как в реализации, так и с точки зрения секретности и целостности приложения);
  • либо сохранять контекст выполнения в каком-то виде на сервере (например, в базе данных), и при следующем вызове его восстанавливать.

По сути, SM реализует последний вариант, но "прозрачным" для приложения способом. Т.е. cgi-приложение не видит управляющих директив SM.Как и следует из названия, SM предназначена для управления состояниями приложения. Под состоянием понимается некоторый набор переменных окружения (environment) cgi-процесса, связанный с его именем (путем запуска) и аргументами. SM располагается между web-сервером и cgi-программой, передает ей выходной поток сервера и переменные окружения, а также осуществляет фильтрацию выходного потока cgi-программы (только для Content-type: text/html). При обнаружении управляющих (для SM) директив, SM выполняет определенные действия по управлению состояниями (сохранение и последующее восстановление, порождение новых состояний и возврат к родительским), а также заменяет в выходном потоке часть URL, модифицируя их для последующего использования. Таким образом, SM формирует дерево состояний, которое, собственно, и создает целостное приложение из отдельных cgi-программ.

В настоящее время SM реализована в виде двух программ - smconn и sm. Web-cервер всегда запускает smconn с аргументами, записанными как продолжение пути.

Например, точка входа приложения может иметь вид:

http://localhost/cgi-bin/mail/smconn/init,
а "внутри" приложения это будет нечто вроде:
http://localhost/cgi-bin/mail/smconn/state&41234123


В свою очередь, smconn соединяется с Unix-domain-socket, "на другом конце" которого "висит" собственно sm. При обнаружении запроса sm запускает отдельный thread на его обслуживание, и уже в нем стартует необходимая cgi-программа.

Таким образом, на обработку каждого запроса стартуется (как минимум:) два процесса - smconn и собственно cgi - программа. Хотя smconn весьма мала и практически не потребляет системных ресурсов, ее запуска можно избежать, если использовать модуль к web-серверу, выполняющий ее функции.

Как видно, приведенная схема не совсем проста и возникает вопрос: почему бы не реализовать функции SM непосредственно в модуле web-сервера? К сожалению, в общем случае это невозможно. По своей семантике, ОДНА sm должна обрабатывать ВСЕ запросы к конкретному приложению. Стандартные web-серверы, например, apache, создают множество копий самих себя для оптимизации обработки запросов, и, хотя этим процессом можно в каких-то пределах управлять, полного контроля нет.

Первая версия SM была сделана на базе известного протокола FastCGI, но выяснилось, что "размножение" процессов сервера "размножает" и обработчики, что недопустимо. Кроме того, имеющаяся у нас (свободная) реализация FastCGI оказалась довольно сложной и неустойчивой...

2. Управляющие директивы SM.

Все управляющие директивы, распознаваемые SM, описываются в виде тегов HTML, а точнее, в виде HTML-комментариев. Это в некоторой степени облегчает расширение SM - нераспознаные контструкции не будут засорять пользовательский интерфейс.
Далее, при описании директив, заключенные в квадратные скобки [ ] части необязательны.
callstatenameglobalbindprint
fcalllocalformexpirequit
scallprivateimgclearquery
returnpubliclimgoption

2.1. Директива вызова call.

Синтаксис:
<!#call program="progname" [return="retname"] [prefix="url_prefix"] [src="url_src"]>
или
<!#fcall program="progname" [return="retname"] [prefix="url_prefix"]>

При использовании вне форм, тег call заменяется на <a href=state&34234234>, при этом создается новое (пустое) состояние, т.е. некоторая заготовка состояния, содержащая лишь имя cgi-программы и ее аргументы.

Например, если во входном потоке стоит:
<!#fcall program="help.sh main_context">Help</a>
то к пользователю попадет нечто вроде
<a href="state&4234234&call">Help</a>

и при активизации этой ссылки SM активизирует соответствующее состояние как дочернее к текущему и запустит программу help.sh c аргументом командной строки main_context. Заметим, что стандартная семантика cgi-вызовов не позволяет передавать аргументы командной строки, что иногда весьма неудобно.

Атрибут return определяет имя переменной окружения, в которую будет помещен результат (см. <!#return>).

Если задан атрибут prefix, то его значение добавляется перед значением href. Это иногда необходимо для управления состояниями "вручную" - например, для смены текущего с точки зрения web-сервера каталога, для изменения прав доступа или перекодировки.

При использовании в формах директива <!#call ...> заменяется на <input type=submit ...> или, если передан атрибут src, на <input type=image ...>, атрибут url_src - исходный URL изображения.

Например,
<!#form>
...
<!#call program="forward.sh" value="forward" size=20>
...
</form>

директива вызова call будет заменена на
<input type=hidden name=_C_1 value="_N_1">
<input type=submit name="_N_1" value="forward" size="20">

или, с использованием атрибута src:
<!#form>
...
<!#call program="forward.sh" value="forward" size=20 src="forward.gif">
...
</form>
директива вызова call будет заменена на
<input type=hidden name=_C_1 value="_N_1">
<input type=image name="_N_1" value="forward" size="20" src="/images/imail/forward.gif">

Атрибут src тега <input type=image ...> принимает значение атрибута imagedir файла конфигураций SM плюс значение атрибута src управляющей директивы <!#call ...>

Директива imagedir файла конфигурации SM (sm.cfg) в данном примере, имеет значение /images/imail См. также <!#form> и директивы файла конфигураций SM (sm.cfg) imagedir

2.2. Директива scall.

Синтаксис:
<!#scall program="program_scall">

Директива используется в программах JavaScript для создания состояний.
Например:
<script language="JavaScript">
...
window.open(<!#scall program="asdf.sh">, ...); ...
</script>
в выходном потоке будет:
<script language="JavaScript">
...
window.open("state&121212&scall", ...); ...
</script>,
где 121212 - номер состояния

2.3. Возврат return.

Синтаксис:
<!#return [return="retval"] [statename="state_name"] [href="localref"] [query="query"] [prefix="url_prefix"]>

return во входном потоке заменяется на ссылку, возвращающую в родительское состояние, например, если родительское состояние имеет номер 1234, то <!#return>back</a>
будет заменено на
<a href="state&1234&return">back </a>.

Атрибут return задает возвращаемое в родительское состояние значение. Это значение будет присвоено переменной окружения, указанной в директиве call
Например,
main.sh ...
<!#call program="file.sh" return="asdf">
...
file.sh:
...
<!#return return="0">
...

Переменной окружения asdf после выполнения cgi-программы file.sh будет присвоено значение 0. Если задан атрибут statename, то возврат производится в состояние с именем "state_name" (см. <!#statename>).

Если задан атрибут href, то его значение добавляется после знака # к результирующему URL (т.е. как ссылка внутри страницы). Значение query добавляется к результирующему URL после знака "?". prefix используется точно так же, как и в <!#call ...>. При возврате в любое состояние все состояния-потомки автоматически уничтожаются.

2.4. Задание имени состояния statename

Синтаксис:
<!#statename "some_name">

Любому новому, вновь созданному состоянию, автоматически присваивается уникальное имя. Директива statename позволяет задать состоянию имя some_name.
Это имя можно впоследствии использовать для возврата в состояние из состояний-потомков.
Например,
mine.sh
...
<!#statename "my_state">
...
<!#call program="file.sh">

file.sh
...
<!#return statename="my_state">
...
(см. <!#return>).

2.5. Создание переменных.

Программа, выполняемая под SM, может определить для себя (и состояний - потомков) переменные окружения и присвоить им значения. Переменные могут иметь область видимости local, public, private и global и создаются управляющей директивой вида:

<!#local   name1=value1 ... nameN=valueN>
<!#private name1=value1 ... nameN=valueN>
<!#public  name1=value1 ... nameN=valueN>
<!#global  name1=value1 ... nameN=valueN>

local переменные принадлежат только состоянию, в котором они созданы.

private переменные принадлежат состоянию, в котором они созданы, но передаются состояниям-потомкам. При этом состояние-потомок не может изменить private переменную предка, т.к. private создаст новую переменную, скрывающую переменную предка.

public переменные передаются по наследству состояниям-потомком и разделяются с ними. Т.е. если состояние-потомок присваивает значение public переменной, то изменяется и значение родительской public-переменной.

global являются public-переменными, принадлежащими самому верхнему (корневому) состоянию. Если несколько переменных имеют одно имя, то приоритет имеет local, затем private, затем public.

Замечание: переменные окружения, общие для всего приложения, можно определить директивой envar файла конфигурации SM sm.cfg.

2.6. Создание форм form

Синтаксис:
<!#form ... >... </form>

Директива <!#form ... >понимает те же атрибуты, что и стандартный тег <form>.
Например, если во входном потоке стоит:
<!#form target="asdf">...</form>
то к пользователю попадет нечто вроде
<form action=state&12345&form target="asdf">,
где 12345 номер текущего состояния. В форме, для создания кнопок передачи можно использовать директиву call. В этом случае управление будет передано cgi-программе, заданной атрибутом program директивы <!#call ...> Но не запрещено и использование стандартных тегов:

<input type=submit ...> и <input type=image ...>.
В последнем случае управление будет передано в эту же форму.

2.7. Создание изображений.

Синтаксис:
<!#img src="url_src" ...>
или
<!#limg src="url_src" ...>

Директивы понимают стандартные для тега <img> атрибуты. В выходном потоке получается:
<img src="dir_for_image/url_src">
или
<img src="dir_for_image/kod_language/url_src"> для директивы <!#limg ...>
url_src - URL изображения.
dir_for_image - задается директивой файла конфигурации sm.cfg imagedir
kod_language - двухбуквенная аббревиатура языка, используемого броузером для отображения содержимого страниц. Язык просмотра задается настройками броузера.

2.8. Директива bind.

Синтаксис:
<!#bind cid="content_ID" program="bind_program [param1 ...]">
Связывает идентификатор ресурса с cgi-программой bind_program обработки этого ресурса.

2.9. Директива expire.

Синтаксис:
<!#expire timeout=timeout_sec>

Устанавливает время timeout_sec в секундах, по истечении которого сбрасывается состояние SM.

2.10. Директива clearquery.

Синтаксис:
<!#clearquery>

Очищает переменную среды QUERY_STRING.

2.11. Директива option.

Синтаксис:
<!#option strict=on|yes|off|no>

Определяет метод обработки SM-ой атрибута href тега
strict=on|yes - "жесткая" обработка атрибута href, т.е., если в cgi-программе
<a href="asdf.sh">Call asdf.sh </a>,
то в выходном потоке так и будет:
<a href="asdf.sh">Call asdf.sh </a>

Если strict=off|no - метод по умолчанию -, то в выходном потоке будет:
<a href="state&12345&call">Call asdf.sh </a>
И к имени asdf.sh будет добавлен путь work_dir_name- рабочий каталог.

2.12. Директива печати print.

Синтаксис:
<!#print program="program_name">
или
<!#print on|off>

Атрибут program определяеет cgi-программу печати. Заменяется на тег-гиперссылка и требует закрывающего тега.

on - разрешает вывод на печать, off - запрещает.
Например,
<!#print program="program_name"> Печать документа </a>
будет заменена на
<a href="state&1234&print"> Печать документа </a>

cgi-программе в STDIN передается поток - текущая страница документа.

2.13. Директива quit.

Синтаксис:
 <!#quit>

Уничтожает все состояния SM и по завершении выполняет cgi-программу с именем quit.

3. Директивы файла конфигурации SM sm.cfg

debuglevellognamealowfdlimitimagedir
end-of-requestserverheaderexpire
pidnameenverworkdirlocale

3.1 debuglevel

Синтаксис: debuglevel <numberlevel>

Устанавливает уровень вывода сообщений в log-файл.

    numberlevel
  • 0 - минимальный (только сообщения об ошибках)
  • 1 - стоит по умолчанию (старт/стоп, прием запроса, старт приложения)
  • 3 - подходящий для отладки
  • 9 - максимальный

3.2 end-of-request

Синтаксис:
end-of-request <eor-string>

Задает строку, используемую для обозначения конца запроса при диалоге с серверами.
Например:
end_of_request "<<<EOR>>>"

3.3. pidname

Синтаксис:
pidname <file-with-pid-name>

Задает имя файла, в котором хранится pid процесса SM
Например,
pidname ./spool/sm.pid

3.4. logname

Синтаксис:
logname <log-file-name>

Задает имя log-файла. Его содержимое зависит от директивы debuglevel. Кроме того, в этот файл попадает вся информация об ошибках SM, старт и стоп машины состояний.
Например,
logname ./spool/sm.log

3.5. server

Синтаксис:
server <"pipe"|"pty"|"socket"> <name><executable-name>[<arg1>... <argN>]

Программа executable-name обрабатывает запросы, посылаемые cgi-программами SM.
pipe|pty|socket - задают тип связи программы со SM.
name - имя обрабатывающей программы, известное машине состояний, а arg1, ..., argN - принимаемые ею параметры.
Например,
server pipe cgi ./progs/cgiutil
или
server pipe users ./progs/dbmutil spool/users

3.6. envar

Синтаксис:
envar <name><value>

Задает общую для всего приложения переменную окружения.
Например,
envar FORTUNE "/usr/games/fortune"

3.7. allow

Синтаксис:
allow <executable-name-1>[ ...<executable-name-N>]

Определяет имена executable-name-1[ ...executable-name-N], как разрешенные точки входа в приложение.
Например,
allow init
Программа init единственная точка входа:
http://last/cgi-bin/mail/smconn/init

3.8. header

Синтаксис:
header <header-string>

Строка HTTP заголовка отклика.

3.9. workdir

Синтаксис:
workdir <work-dir-name>

Рабочий каталог cgi-программ
Например,
workdir /usr/program/cgi-bin/mail/progs

3.10. fdlimit

Синтаксис:
fdlimit <number>

Задает максимальное количество открытых файловых дескрипторов. Если количество открытых дескрипторов превышает number, то не позволяет открывать новые.

3.11. expire

Синтаксис:
expire <minuts>

Устанавливает время minuts в минутах, по истечении которого сбрасывается состояние SM. Это значение принимается по умолчанию, если исходный URL не содержит управляющей директивы expire.

3.12. locale

Синтаксис:
locale <locale-name> <locale-file>

Задает путь для файлов сообщений.

SM проверяет настройки броузера - текущий язык просмотра - и используя файл сообщений, заменяет все вхождения конструкции _(текст сообщения)_ на соответствующие установленному языку просмотра. Например, если в cgi-программе встречается конструкция _(Press any key to continue...)_ то в выходной поток в зависимости от настроек попадет en Press any key to continue... ru Для продолжения работы нажмите любую клавишу...

3.13. imagedir

Синтаксис:
imagedir <dir-for-images>

Задает каталог для изображений.
Например,
imagedir /images/imail

© ООО "Инженерно-Техническая Компания" (ИТК) 2006
426072, Удмуртская республика, Ижевск а/я 1247, uri at itk dot ru