Skip to content

kalloc/libqtp

Repository files navigation

Платформа Q.

QTP 1.3.0 (UNSTABLE)
(Q-Lang dialect version 2.1 preview)

1. Введение.

(ВНИМАНИЕ!!! ДАННЫЙ РЕЛИЗ СЧИТАЕТСЯ НЕСТАБИЛЬНЫМ И ВЫПУСКАЕТСЯ ТОЛЬКО
ДЛЯ ТЕСТИРОВАНИЯ НОВЫХ ФИЧ ДИАЛЕКТА 2.1. СКОРЕЕ ВСЕГО НЕ ВСЕ ОПИСАННОЕ
ТУТ БУДЕТ РАБОТАТЬ ДО ВЫХОДА РЕЛИЗА 1.4.0, А ЧТО-ТО И ВОВСЕ ИЗМЕНИТСЯ)

(ВНИМАНИЕ!!! Начиная с версии 1.3.0 необходимо инклудить только:
#include <qtp.h>, а линковать к проекту нужно только -lfcgi -lqtp,
библиотека cgix теперь входит в libqtp)

Платформа Q это совокупность программных средств для разработки
CGI-приложений, рассчитанных на высокую нагрузку. В состав платформы входят:

-	FastCGI система организации работы CGI-приложений, как отдельных
	программ (демонов/сервисов), которые после запуска постоянно
	находятся в памяти и обрабатывают приходящие к ним от web-сервера
	запросы.
-	QTP (или Q-Lang) препроцессор шаблонов, рассчитанных на высокую
	нагрузку и оптимизированных для встраивания непосредственно в код
	программы.
-	CGIX модифицированная версия CGIC, оптимизированная для работы с
	FastCGI и QTP (или Q-Lang).
-	QCM система динамического кэширования
-	QQM система написания плагинов для построения запросов напрямую из
	шаблонов. (!!!не реализовано!!!)
-	QSM система сессионного движка

Преимущества использования платформы Q:

-	Высокая скорость работы приложений.

-	Наличие всего необходимого инструментария для быстрого построения
	cgi-приложений.
	
-	Возможность post-кэширования обработанных запросов с помощью сохранения
	сгенерированного контента в обычные .html файлы.
	
-	Возможность автоматического динамического кэширования (libqcm).

-	Возможность получения "Content-Length" для результата работы,
        а стало быть возможность использования http-акселераторов на
	полную мощность.
	
-	Возможность посылать SQL и подобные запросы напрямую из шаблонов.
	(!!!не реализовано!!!)
	
-	Возможность написания плагинов для любых реляционных баз данных.
	(!!!не реализовано!!!)
	
-	Система QSM (session manager) позволяет с помощью сессий решать
	проблемы с секурной авторизацией. 
	(!!!реализовано, но не оттестировано!!!)

Некоторые особенности использования платформы Q:

-	Необходимо учитывать цикличность работы приложений при работе с памятью.
-	Необходимо тщательно продумывать шаблоны и их обработчики в связи со
	строгостью синтаксиса.
-	Желательно оперативные данные хранить в памяти приложения.
	(то есть, не использовать для динамических данных RDBMS)
-	Устанавливать соединение с СУБД один раз при старте приложения.
-	Необходимо знание языка C на достаточно высоком уровне.
-	Необходимо детальное понимание философии QPLATFORM.

2. Синтаксис шаблонов препроцессора QTP.

	Сам .qtp скрипт фактически является прокомментированным .html, в
комментариях которого содержится служебная информация для построения
шаблонов (.c и .h)

	Синтаксис .qtp довольно прост.Все служебные команды располагаются после
выделенной части .html, чтобы определить ее назначение и обработку. В шаблоне
.qtp должно содержаться фиксированное кол-во proc'едур для совместимости с
шаблонным обработчиком, который пишется на C.

Существует четыре блок-делимитера: proc, loop, execute, extern, intern и query
Синтаксис:
<!-- proc <имя процедуры> [тип параметр 1],[тип параметр 2],...; -->
Делимитер процедуры (обработчик <имя модуля>_<имя_процедуры>_do)

<!-- loop <имя процедуры> [тип параметр 1],[тип параметр 2],...; -->
Делимитер цикла (обработчик <имя модуля>_<имя_цикла>_do)

<!-- extern <имя модуля>_<имя процедуры>; -->
Делимитер внешнего вызова (обработчик <имя модуля>_<имя процедуры>_do

<!-- intern <имя процедуры>; -->
Делимитер внутренней функции (обработчик отсутствует)

<!-- query <имя модуля> <запрос>; -->
Делимитер запроса к базе (!!!НЕ РЕАЛИЗОВАН!!!)

<!-- source <имя файла>; -->
Вставляет #include в генериуемый файл .c

<!-- use <имя модуля>.q; exec <имя процедуры>; -->
Делимитер исполнителя, который может вызывать внешние блоки из <имя модуля>.q

<!-- lib <имя процедуры> [тип параметр 1],[тип параметр 2],...; -->
Делимитер библиотечной функции (используется use/exec)

Описатели блоков-делимитеров ставятся после блока и означают его завершение.
Начало блока находится либо в начале исходного текста, либо после очередного
делимитора.

Внутри блока proc (exec, loop) допустимы следующие операторы:
{var "<format>",<variable>,<variable>...} - вставить переменную (как printf)
{if <expression>}...[{else}]...{/if} - условие (только внутри блока)
{include <file>} - вставить внешний файл (как то header и footer)

Внутри блока query допустимы следующие операторы:
{res <num>} - вставляет порядковый номер результата из запроса

Пример #1:
<!-- proc header char *title; -->

Пример #2:
<!-- loop body char *name,int age,char *sex; -->

Пример #3:
<!-- extern news_head; -->

Пример #4:
<!-- intern head; -->

Пример #5 (не утверждено):
This is Users:
{if isform}
<!-- intern users_begin; -->
Name: {res 1}  Age: {res 2}
<!-- query mysql select name,age from users where adminid=12; -->
{else}
No users in this class...
{/if}
<!-- proc userlist int isform; -->

3. Пример проекта.

	Назначение QTP - обеспечение максимального удобства программирования
и построения шаблонов. То есть, шаблоны, созданные для QTP легко
просматриваются в браузере как обычный html.

Рассмотрим шаблон:

<HTML>
<HEAD>
<TITLE>Example</TITLE>
</HEAD>
<BODY>
<TABLE>
<!-- intern header; -->
<!-- extern news_body; -->
<TR><TD>Имя: {if name}{var "%s",name}{/if}</TD>
<TD>Возраст: {var "%s",age}</TD></TR>
<!-- proc body char *name,char *age; -->
</TABLE>
</BODY>
</HTML>
<!-- intern footer; -->

Теперь подадим комманду:
qtp -sanketa.qtp -oanketa

Получаем два файла anketa.c и anketa.h:

В файле anketa.c функции, объявленные как extern, соответствуют определенным
в шаблоне proc'едурам с постфиксом _do и префиксом anketa_ (anketa_header_do,
ankeata_body_do, anketa_footer_do) и  применяются для описания call-back
обработчиков. Также в шаблоне вызывается внешний шаблонный элемент body из
модуля news: void news_body_do();
При выводе параметра name проверяется его неравенство 0 ({if..)

В файле anketa.h определен порядок парсинга элементов шаблона, а также
объявлены функции, которые нужно вызывать в соответствующих call-back
обработчиках (например, обработчик anketa_header_do() должен оперировать
только функцией заполнения anketa_header, использование кросс-вызова например
функции anketa_footer() будет считаться плохим стилем, хотя работать конечно
будет).


anketa.h:
/* Generated from [anketa.qtp] by QTP (version 1.0rc1) [release candidate] */
void anketa_header ();
void anketa_body (char *name, char *age);
void anketa_footer ();

void anketa();

Пример обработчика:

main.c:
#include <qtp.h>
#include "anketa.h"

// У нас header описан как intern, он не требует обработчика
// void anketa_header_do () {// Обработчик anketa_head
// 	anketa_header();
// }

void anketa_body_do () { // Обработчик anketa_body
	int i; // Рассматривать как пример!
	char st1[200],st2[200];
	for (i=0;i<20;i++) {
		snprintf (st1,200,"user-%d",i);
		snprintf (st2,200,"%d",i);
		anketa_body (st1,st2); // Заполняем anketa_body(name,age);
	}
}

// У нас footer описан как intern, он не требует обработчика
// void anketa_footer_do () { // Обработчик anketa_bottom
// 	anketa_footer();
// }

int cgiInit () {
	// Инициализация FastCGI демона.
	return 0;
}

int cgiMain () {
	printf ("Content-Type: text/html\n\n");
	anketa();
	return 0;
}

а также 

void news_body() {
...
Тут находится call-back функция шаблона news элемента body
...

}
    
В результате получаем FastCGI демон, который выводит следующую информацию:

<HTML>
<HEAD>
<TITLE>Example</TITLE>
</HEAD>
<BODY>
<TABLE>

<TR><TD>Имя: user-0</TD><TD>Возраст: 0</TD></TR>

<TR><TD>Имя: user-1</TD><TD>Возраст: 1</TD></TR>

<TR><TD>Имя: user-2</TD><TD>Возраст: 2</TD></TR>

 [пропущено несколько строк...]

<TR><TD>Имя: user-18</TD><TD>Возраст: 18</TD></TR>

<TR><TD>Имя: user-19</TD><TD>Возраст: 19</TD></TR>
 
</TABLE>
</BODY>
</HTML>

4. Параметры запуска препроцессора qtp.

qtp 1.3.0
  
-h              --help          Вывод справки по опциям qtp

-V              --version       Версия протокола и номер релиза.

-sSTR           --source=STR    Исходный текст шаблона .qtp

-oSTR           --out=STR       Имя проекта. (по умолч source до первой точки)

-cSTR           --out-c=STR     Имя результирующего файла .c
                                (если не указано, то <имя проекта>.c)

-rSTR           --out-h=STR     Имя результирующего файла .h
                                (если не указано, то <имя проекта>.h)

-fSTR           --file=STR      Данная опция применяется для того, чтобы при
                                отработке шаблона в рабочих условиях вывод
                                происходил не только на stdout, но и в указанный
                                файл-дескриптор (FILE *). Опция может быть
                                указана несколько раз. Применяется для
                                кэширования результата работы CGI-приложения.

-n              --nostd         Данная опция отключает вывод на stdout
                                сгенерированной пары (.c .h). Применяется
                                для оффлайновой генерации шаблонов, когда вывод
                                на экран не требуется.

-l		--contentlength Выводить Content-Length для каждой итерации
				демона.

-i		--include=STR   Делает #include "%s" в сгенерированный файл .c

-p		--prefix=STR    Добавляет ко всем функциям префикс

		--nocgix        Отключает систему cgix.

-u		--userarg       Добавляет void *userarg к вызову всех процедур

-m		--module	Определяет модуль в котором искать описания
                                query плагинов. (идентично --include, но
				с добавлением в конец ".h")

5. Использование системы динамического кэширования QCM.

    Для того, чтобы начать использовать QCM Вам необходимо собрать
    Ваши шаблоны с ключом -f<имя переменной "FILE *">

    Далее описываем поведение кэшера, например:
    
    FILE *cachef=NULL; // Обязательно прировнять файл к NULL!

    qcm_contentlength_set (size_t разм. внутр. кэша, size_t разм. внеш. кэша);
    Определяет размер буферов для работы QTP с Content-Length.
    Если буфера не будет хватать, выведется только та часть, которая
    поместилась в буфер.
    
    qcm_init(); // Вызывается в самомо начале ТОЛЬКО 1 РАЗ
    // Также вызывается, если используется система просчета Content-Length

    qcm_dir(char *); // Определяем каталог в котором будет лежать кэш

    qcm_contentlength_on(); // Определяет то, что у нас будет выводиться
    content-length для закэшированных данных

    qcm_contentlength_off(); // Определяет то, что у нас не будет выводиться
    content-length для закэшированных данных

    Далее:

    qcm_checker(параметры в формате printf) выставляется timestamp тестер для
    определения устаревания кэша.

    qcm_set(char *); // Определяем по какому полю (GET/POST) производить
    кэширование (может повторять несколько раз, для определения нескольких
    полей.

    qcm_set(NULL); // Сбрасывает список кэширования.

    qcm_open(параметры в формате printf); // Определяет основное название
    файла кэша.
    (если вернуло NULL значит сработало кэширование, больше ничего
    делать не нужно делаем выход)
    возвращенное значение присваивается переменной FILE *, которая определеня
    при вызове qtp.

    qcm_close (FILE *); // Завершить работы qcm с файлом кэша.

    qcm_clear (); // Сбрасывает кэш для группы выбранной qcm_checker()

Задача: Нам нужно кэшировать ленту новостей:
Решение:

FILE *cachef; // Файл кэша (qtp -fcachef - чтобы механизм начал работать)

int cgiInit ()
{
	qcm_contentlength_set (500000,65535);
	// Устанавливаем размеры внутренних буферов
	// Внутренний - 500000, временный - 65535
	qcm_contentlength_on (); // Включаем поддержку content-length
	qcm_dir("/tmp/cache"); // Выставляем директорию для кэша
	qcm_init();
}

int cgiMain ()
{
	... // Проверки определили, что мы должны вывести новости
	qcm_checker ("lenta%d",lenta_id);
	qcm_set (NULL);
	qcm_set ("offset"); // для определения имени кэша используем смещение
	cachef = qcm_open("lenta%d",lenta_id);
	if (!cachef) return 0; // Сработал кэш, ничего делать больше не надо
	lenta(); // Вызываем QTP элемент "lenta"
	qcm_close (&fl);
	... // Проверки определили, что добавилась новая новость
	qcm_checker ("lenta%d",lenta_id);
	qcm_clear ();
	...
}

6. Использование сессий внутри проекта на QTP.

Внутри cgiInit() нужно вызвать qsm_init() если Вы собираетесь использовать
сессии внутри вашего проекта.

qsm_init("<путь к каталогу с сессиями>","<имя группы сессий>",<время жизни>);
время жизни сессий указывается в секундах.

Например:
qsm_init("/tmp/sessions","myproject",1200);

Далее внутри cgiMain() используются следующие функции:

qsm_init_session() // Вставляется до вывода хидеров или во время их вывода
на stdout

qsm_set_param("<имя параметра>","<значение>");// Установить значение параметра.

qsm_get_param("<имя параметра>"); // Запросить значение параметра
Если не найдено, возвращает NULL.

qsm_del_param("<имя параметра>"); // Удалить значение и параметр

Для конкретной группы CGIX приложений всегда автоматически запускается демон,
который производит уборку мусора (удаление устаревших сессий).
(группа определяется во время вызова qsm_init() )

7. Заключение.

- У Вас появились новые идеи?
- Вы нашли ошибку в программе?
- Вы хотите принять участие в разработке платформы Q?

Пишите: [email protected]

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published