R3
================
R3 — это библиотека маршрутизатора URL с высокой производительностью, поэтому она реализована на языке C. Она компилирует пути R3Route в префиксное дерево. Используя построенное во время запуска дерево, вы можете эффективно направить путь к контроллеру.
/blog/post/{id} по умолчанию используется регулярное выражение [^/]+.
/blog/post/{id:\d+} вместо стандартного используется регулярное выражение \d+.
#include <r3/r3.h>
// создать дерево маршрутизатора с ёмкостью 10 дочерних элементов (эта ёмкость может расти динамически)
R3Node *n = r3_tree_create(10);
int route_data = 3;
// вставить путь R3Route в дерево маршрутизатора
r3_tree_insert_path(n, "/bar", &route_data); // игнорировать длину пути
r3_tree_insert_pathl(n, "/zoo", strlen("/zoo"), &route_data );
r3_tree_insert_pathl(n, "/foo/bar", strlen("/foo/bar"), &route_data );
r3_tree_insert_pathl(n ,"/post/{id}", strlen("/post/{id}") , &route_data );
r3_tree_insert_pathl(n, "/user/{id:\\d+}", strlen("/user/{id:\\d+}"), &route_data );
// если вы хотите отловить ошибку, вы можете вызвать расширенную функцию пути для вставки
int data = 10;
char *errstr = NULL;
R3Node *ret = r3_tree_insert_pathl_ex(n, "/foo/{name:\\d{5}", strlen("/foo/{name:\\d{5}"), NULL, &data, &errstr);
if (ret == NULL) {
// ошибка вставки
printf("error: %s\n", errstr);
free(errstr); // errstr создан из `asprintf`, поэтому его нужно освободить вручную.
}
// давайте скомпилируем дерево!
char *errstr = NULL;
int err = r3_tree_compile(n, &errstr);
if (err != 0) {
// сбой
printf("error: %s\n", errstr);
free(errstr); // errstr создан из `asprintf`, поэтому его нужно освободить вручную.
}
// дамп скомпилированного дерева
r3_tree_dump(n, 0);
// сопоставить маршрут
R3Node *matched_node = r3_tree_matchl(n, "/foo/bar", strlen("/foo/bar"), NULL);
if (matched_node) {
int ret = *( (int*) matched_node->data );
}
// освободить дерево
r3_tree_free(n);
Захват динамических переменных
Если вы хотите захватить переменные из регулярного выражения, вам необходимо создать объект match_entry
и передать объект функции r3_tree_matchl
, захваченные переменные будут помещены в структуру записи соответствия:
match_entry * entry = match_entry_create("/foo/bar");
// освободите запись соответствия
match_entry_free(entry);
И вы даже можете указать ограничение метода запроса:
entry->request_method = METHOD_GET;
entry->request_method = METHOD_POST;
entry->request_method = METHOD_GET | METHOD_POST;
При использовании match_entry
, вы можете сопоставить R3Route с функцией r3_tree_match_entry
:
R3Node * matched_node = r3_tree_match_entry(n, entry);
Освобождение памяти
Чтобы освободить память, вы можете вызвать r3_tree_free(R3Node *tree)
, чтобы освободить всю древовидную структуру, объекты node*
, edge*
, route*
, которые были вставлены в дерево, будут освобождены.
Маршрутизация с условиями
// создать дерево маршрутизатора с 10 дочерними элементами (эта ёмкость может расти динамически)
n = r3_tree_create(10);
int route_data = 3;
// вставить путь R3Route в дерево маршрутизатора
r3_tree_insert_routel(n, METHOD_GET | METHOD_POST, "/blog/post", sizeof("/blog/post") - 1, &route_data );
char *errstr = NULL;
int err = r3_tree_compile(n, &errstr);
if (err != 0) {
// сбой
printf("error: %s\n", errstr);
free(errstr); // errstr создан из `asprintf`, поэтому его нужно освободить вручную.
}
// в вашем обработчике HTTP-сервера
// создайте запись соответствия для захвата динамических переменных.
match_entry * entry = match_entry_create("/blog/post");
entry->request_method = METHOD_GET;
R3Route *matched_R3Route =
``` **R3Route: оптимизация и производительность**
r3_tree_match_route(n, entry);
matched_route->data; // get the data from matched route
// free the objects at the end
match_entry_free(entry);
r3_tree_free(n);
Slug — это заполнитель, который захватывает строку из URL в качестве переменной. Slugs будут скомпилированы в шаблоны регулярных выражений.
Slugs без шаблонов (например, /user/{userId}) будут скомпилированы в шаблон [^/]+.
Чтобы указать шаблон slug, вы можете написать двоеточие для разделения имени slug и шаблона:
"/user/{userId:\\d+}"
Приведённый выше R3Route будет использовать \d+ в качестве шаблона.
Оптимизация
Простые регулярные выражения оптимизируются через транслятор паттернов regexp, который переводит простые паттерны в небольшие и быстрые сканеры.
Используя этот метод, r3 уменьшает накладные расходы на сопоставление библиотеки pcre2.
Оптимизированные паттерны: [a-z]+, [0-9]+, \d+, \w+, [^/]+, [^-]+ или .*.
Slugs без указанного регулярного выражения будут скомпилированы в [^/]+ шаблон. Поэтому он также оптимизирован.
Сложные регулярные выражения по-прежнему будут частично использовать libpcre2 для сопоставления URL.
Производительность
Результаты тестов производительности от stevegraham/rails' PR:
omg 10462.0 (±6.7%) i/s - 52417 in 5.030416s
И результаты теста маршрутизатора:
omg 9932.9 (±4.8%) i/s - 49873 in 5.033452s
R3 использует тот же путь данных R3Route для тестирования, и вот тест:
3 runs, 5000000 iterations each run, finished in 1.308894 seconds
11460057.83 i/sec
Функция префиксного сопоставления
| Функция префикса | Описание |
| --- | --- |
| r3_tree_* | Операции с деревом, которые требуют узла для управления всем деревом |
| r3_node_* | Одноузловые операции, которые не проходят через собственных детей или родителей |
| r3_edge_* | Краевые операции |
| r3_route_* | Маршрутные операции, необходимые только тогда, когда дерево определено маршрутами |
| match_entry_* | Сопоставление операций ввода, match_entry — это просто параметры запроса |
Визуализация маршрутов с помощью Graphviz
API r3_tree_render_file позволяет визуализировать всё дерево R3Route в виде изображения.
Для использования graphviz необходимо включить его при запуске configure:
./configure --enable-graphviz
Пример кода генерации вывода графа:
```c
R3Node * n = r3_tree_create(1);
r3_tree_insert_path(n, "/foo/bar/baz", NULL);
r3_tree_insert_path(n, "/foo/bar/qux", NULL);
r3_tree_insert_path(n, "/foo/bar/quux", NULL);
r3_tree_insert_path(n, "/foo/bar/corge", NULL);
r3_tree_insert_path(n, "/foo/bar/grault", NULL);
r3_tree_insert_path(n, "/garply/grault/foo", NULL);
r3_tree_insert_path(n, "/garply/grault/bar", NULL);
r3_tree_insert_path(n, "/user/{id}", NULL);
r3_tree_insert_path(n, "/post/{title:\\w+}", NULL);
char *errstr = NULL;
int err;
err = r3_tree_compile(n, &errstr);
if (err != 0) {
// fail
printf("error: %s\n", errstr);
free(errstr); // errstr is created from `asprintf`, so you have to free it manually.
}
r3_tree_render_file(n, "png", "check_gvc.png");
r3_tree_free(n);
Результат:
Или вы даже можете экспортировать его в формате dot:
digraph g {
graph [bb="0,0,205.1,471"];
node [label="\N"];
"{root}"
В тексте запроса используется язык программирования C. ### Graphviz Related Functions
```c
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
int r3_tree_render(const R3Node * tree, const char *layout, const char * format, FILE *fp);
int r3_tree_render_dot(const R3Node * tree, const char *layout, FILE *fp);
int r3_tree_render_file(const R3Node * tree, const char * format, const char * filename);
Можно преобразовать всю древовидную структуру в формат вывода JSON.
Пожалуйста, запустите configure
с опцией --enable-json
.
Вот пример кода для генерации строки JSON:
json_object * obj = r3_node_to_json_object(n);
const char *json = r3_node_to_json_pretty_string(n);
printf("Pretty JSON: %s\n",json);
const char *json = r3_node_to_json_string(n);
printf("JSON: %s\n",json);
пока не реализовано
// Вот структура данных путей
$paths = [
'/blog/post/{id}' => [ 'controller' => 'PostController' , 'action' => 'item' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'list' , 'method' => 'GET' ] ,
'/blog/post' => [ 'controller' => 'PostController' , 'action' => 'create' , 'method' => 'POST' ] ,
'/blog' => [ 'controller' => 'BlogController' , 'action' => 'list' , 'method' => 'GET' ] ,
];
$rs = r3_compile($paths, 'persisten-table-id');
$ret = r3_dispatch($rs, '/blog/post/3' );
list($complete, $route, $variables) = $ret;
// сопоставленные условия ещё не выполнены
list($error, $message) = r3_validate($route); // проверка условий R3Route
if ( $error ) {
echo $message; // "Method not allowed", "...";
}
sudo apt-get install check libpcre2 libpcre2-dev libjemalloc-dev libjemalloc1 build-essential libtool automake autoconf pkg-config
sudo apt-get install graphviz-dev graphviz # если вам нужен graphviz
./autogen.sh
./configure && make
sudo make install
Теперь мы поддерживаем дистрибутивы на основе debian!
sudo apt-get install build-essential autoconf automake libpcre2-dev pkg-config debhelper libtool check
mv dist-debian debian
dpkg-buildpackage -b -us -uc
sudo gdebi ../libr3*.deb
./configure --enable-check
make check
./configure --enable-graphviz
./configure --with-malloc=jemalloc
PPA для libr3 можно найти по адресу https://launchpad.net/~r3-team/+archive/libr3-daily.
Node.js
Ruby
Это программное обеспечение выпущено под лицензией MIT.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )