logo

Выполнение скриптов на сервере в FileMaker версий 9 – 12

Автор: Андрей Волков.

В 13 версии появилась новая команда Perform Script On Server (в англоязычных форумах кратко называют PSOS). Разработчики с готовностью стали применять новую возможность в своих проектах. Действительно, удобно и часто необходимо по многим причинам:

  • Выполнить некую процедуру так, чтобы это было не заметно пользователю
  • Выполнить сложный расчет, используя мощности сервера, и быстро получить его результат.
  • Ускорить работу, если требуется некая реакция системы на действия пользователя (отправка почтового уведомления, логирование действий), но при этом нет необходимости заставлять пользователя дожидаться завершения работы скрипта.

К сожалению, клиенты не всегда имеют возможность перейти на новую версию продукта. К счастью, исполнять скрипт на сервере можно и в более ранних версиях FileMaker. Процедура, как выяснилось, имеет некоторые подводные камни, и только длительный опыт позволяет научиться грамотно и оптимально использовать эту возможность. Попробую рассказать о моем опыте и моих выводах.

Что следует знать об исполнении скрипта на сервере?

Если вы используете вариант PSOS, то в этом случае скрипт запускается от лица того пользователя, который запустил команду в своем приложении. Функция Get(AccountName) отработает корректно.

Важно также не забывать, что если в базе данных назначен стартовый скрипт, то при запуске PSOS будут выполнены два скрипта: сначала стартовый, затем PSOS (то же самое происходит при запуске шедул на сервере). Если нет никакой необходимости в предварительном запуске стартового скрипта, то следует позаботиться о том, чтобы сервер игнорировал стартовый скрипт и выполнял только PSOS.

Для этого в стартовом скрипте в самом начале пишем:

If[ LeftWords ( Get(ApplicationVersion); 1 ) = «Server»]
       Exit Script
End If

Следует помнить о том, что входной точкой для исполнения скрипта на сервере будет либо лэйаут, к которому придет в итоге стартовый скрипт (если он не игнорируется), либо лэйаут, открываемый по умолчанию.

Результат исполнения скрипта, если он явно указан в команде Exit Script [Result], доступен в клиентском приложении (функция Get(ScriptResult)).

=====================================================

Для альтернативного запуска скрипта на сервере используется HTTP-запрос (веб-запрос) вида:

http://192.168.123.101/fmi/xml/fmresultset.xml?-db=employees&-lay=departments&-findall&-script=myscript&-script.param=Smith%7CChatterjee%7CSu

в основном адресе которого (до знака вопроса) должен быть указан адрес хоста, а в параметрах указываются:

— имя базы данных (db)
— стартовый лэйаут (lay)
— имя скрипта (script)
— параметр скрипта (script.param)

HTTP запрос – это то, что делает браузер, если мы набираем некий адрес в адресной строке.

Для тестирования мы будем, разумеется, использовать браузер, это удобнее всего. Для практического применения используются команды Insert From URL (12 версия файлмейкера) либо Set Web Viewer.

Ответ от сервера поступает в виде XML. В браузере мы видим текст XML. Если Insert From URL осуществляется в текстовое поле, то получим тот же текст, что и в браузере. Если insert делается в контейнер, то сохранится файл XML.

Что содержит в себе этот самый XML?

Просто данные той страницы, на которой скрипт завершил свою работу. То есть если мы запустим скрипт в приложении FileMaker Pro, дождемся завершения и выполним команду File – Export Records (save as XML), то получим точно такой же XML.

Важно обратить внимание на следующее:

  • Если результирующий лэйаут содержит много срок и полей (много данных), то мы получим в ответ на запрос огромную простыню ненужного нам текста. Этот текст будет долго передаваться от сервера приложению и мы получим ощутимую задержку. Более того, если объем данных слишком велик, то служба Web Publishing сервера может обрушиться и придется перезагружать сервер.
  • В этом ответе мы не можем найти никакой информации о том, с каким результатом был выполнен скрипт.

Для того, чтобы предотвратить несчастные случаи и получить максимальную пользу от применения запросов к серверу, предлагается сделать следующее. В файле  базы данных создаем таблицу RESULT, в которой есть всего одно поле RESULT (глобальное). Скрипт, который выполняется на сервере, должен в самом конце выполнить:

— перейти в лэйаут Result
— вставить в поле Result результат исполнения скрипта
-выйти из скрипта

В таком случае получаем двойной бонус. Во-первых, запрос возвращает нам очень небольшой XML вот с таким текстом:

<FMPXMLRESULT xmlns=»http://www.filemaker.com/fmpxmlresult»>
<ERRORCODE>0</ERRORCODE>
<PRODUCT BUILD=»6/21/2012″ NAME=»FileMaker Web Publishing Engine» VERSION=»12.0.2.228″/>
<DATABASE DATEFORMAT=»MM/dd/yyyy» LAYOUT=»result» NAME=»employees» RECORDS=»1″ TIMEFORMAT=»HH:mm:ss»/>
<METADATA>
<FIELD EMPTYOK=»YES» MAXREPEAT=»1″ NAME=»RESULT» TYPE=»TEXT»/>
</METADATA>
<RESULTSET FOUND=»1″>
<ROW MODID=»0″ RECORDID=»1″>
<COL>
<DATA>222</DATA>
</COL>
</ROW>
</RESULTSET>
</FMPXMLRESULT>

Поскольку передается небольшой объем данных, на процедуру трансфера данных тратится очень мало времени. И нет риска «обрушить» сервер.

Во-вторых, в этом ответе всего один раз встречается тег <DATA></DATA> ; очень легко, используя специальную кастом-функцию, извлечь содержимое этого тега. В приведенном примере содержимое равно 222. Это и был возвращенный скриптом Script Result.

Пример кастом функции:

Cut_tags(text; tag1; tag2)

// Cut_tags(text; tag1; tag2)
// returns content from TEXT between TAG1 and TAG2

Let(
[
tag_len = Length(tag1);
start = Position(text; tag1;1;1) + tag_len;
end = Position(text;tag2;start;1)];

Middle(text; start; end — start)
)

Итак, что требуется для запуска скрипта на сервере через веб-запрос.

  • На самом сервере в разделе Web Publishing следует включить опцию Enable XML publishing. Убедиться, что служба Web Publishing активна.
  • В файле базы данных, в котором будет запускаться скрипт, включить «гостевой» [Guest] аккаунт, который будет использоваться для запуска скрипта на сервере. Важно, чтобы в настройках Privilege Set этого аккаунта была активирована привилегия Access via XML Web Publishing.
  • В файле базы данных для выполнения скрипта нам потребуется специальная таблица (Result), специальный лэйаут (result) и собственно исполняемый скрипт.
  • В клиентском файле на лэйауте, из которого запускается скрипт, должно быть размещено глобальное текстовое поле RESULT, в которые будут помещены данные в результате выполнения команды Insert From URL, либо Web Viewer.

Несколько важных примечаний.

1) Может показаться, что требование иметь на каждом лэйауте поле Result или web-viewer как-то непосильно усложняет задачу. Особенно кошмарным представляется этот вариант в версиях ниже 12, где объекты нельзя вынести за границы лэйаута. Но можно уверенно обойти это ограничение. Можно сконструировать и добавить во все проекты специальный служебный файл. Он содержит всего одну таблицу и всего одно поле. Не содержит пароля (автологин при входе). Его задача выполнить запрос к серверу, извлечь результат и передать этот результат на выходе из скрипта. Смысл трюка в том, что скрипты, запускаемые из внешнего файла всегда запускаются в отдельном окне и это окно невидимо.

2) Исполнение скрипта на сервере путем XML запроса имеет то преимущество, что можно запустить любой скрипт в ЛЮБОМ файле. Не требуется никакой связи между файлом, в котором запрос формируется и файлом, в котором скрипт выполняется. Таким способом можно из любого локального файла отправить команду, которая заставит исполниться скрипт в любом файле на любом сервере.

3) С другой стороны видны и ограничения:

  • сложно передать в скрипт несколько параметров, вообще сложно передать в качестве параметра какой-то сложный длинный текст.
  • если требуется, то в качестве параметра придется передавать аккаунт, так как сервер не распознает, кто именно из пользователей прислал запрос на исполнение.
  • нельзя изменять название скрипта, который передается в строке запроса.
  • в качестве лэйаута, который передается в запросе, лучше использовать служебный лэйаут Result.
  • запрос к серверу требует активации гостевого (Guest) аккаунта. И он должен быть «заточен» исключительно под веб-запросы.

4 комментария

  1. Отличная идея и статья. Однако не совсем понятно, зачем для возврата результата исполнения скрипта использовать специальный отдельный файл. Достаточно, иметь просто специальную таблицу result в файле, с соответствующим лайотом и туда переходить при завершении исполняемого на сервере скрипта. Такую таблицу можно использовать и для логирования исполнения скрипта, создавая запись в result по завершении. Только надо не забывать сделать find set только текущую запись, чтобы назад не вернулся xml со всем записями.

  2. Можно различным способом применять веб-запросы. В том числе и так, как описано в комментарии выше. Этот способ даже будет предпочтительнее, если нужно передать в скрипт несколько параметров. В этом случае алгоритм будет таким:
    сначала создается запись в таблице Result (в ней может быть несколько полей). В специальное поле Code можно записать код скрипта, в поля param1; param2; param3 можно записать параметры скрипта. Затем в веб-запросе достаточно будет только указать идентификатор записи. Специальный скрипт на сервере перейдет в таблицу Result, по переданному идентификатору найдет нужную запись, по полю Code определит скрипт, который нужно будет запустить следом, вызовет этот скрипт с параметрами, которые содержатся в полях param1; param2; param3. После исполнения главного скрипта специальный скрипт прочитает его результат и запишет его в поле Result.
    В клиентском приложении достаточно дождаться завершения Insert From URL. После этого можно прочитать содержимое Result в текущей записи: это результат исполнения скрипта.

  3. Хитрость же со специальным служебным файлом можно использовать, а можно и не использовать. Трюк нужен для того, чтобы вызов запроса был незаметным. Особенно актуально для 11 и более ранних версии файлмейкера, запускаемых в ОС Windows.

    1. Если скрипт работает на сервере, то нам не нужно заботится о том, кто куда возвращается и в каком окне это происходит. В пользовательском лайоте мы останемся там же где и были в момент запуска скрипта.

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *

9 + 1 =