-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
421 lines (306 loc) · 13.1 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
Платформа 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]