1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/mirrors-r3

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
README.md 14 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 30.11.2024 12:29 74c6cb4

R3

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

Build Status

Coverage Status

R3 — это библиотека маршрутизатора URL с высокой производительностью, поэтому она реализована на языке C. Она компилирует пути R3Route в префиксное дерево. Используя построенное во время запуска дерево, вы можете эффективно направить путь к контроллеру.

Требования

Требования к сборке

  • autoconf
  • automake
  • check
  • pkg-config

Требование к среде выполнения

  • pcre2
  • (необязательно) graphviz версии 2.38.0 (20140413.2041)
  • (необязательно) libjson-c-dev

Синтаксис шаблона

/blog/post/{id}      по умолчанию используется регулярное выражение [^/]+.
/blog/post/{id:\d+}  вместо стандартного используется регулярное выражение \d+.

API

#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);

Результат:

Imgur

Или вы даже можете экспортировать его в формате 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 Output

Можно преобразовать всю древовидную структуру в формат вывода 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);

Использование в PHP

пока не реализовано

// Вот структура данных путей
$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

Включение Graphviz

./configure --enable-graphviz

С jemalloc

./configure --with-malloc=jemalloc

Ubuntu PPA

PPA для libr3 можно найти по адресу https://launchpad.net/~r3-team/+archive/libr3-daily.

Привязки для других языков

Node.js

Ruby

Лицензия

Это программное обеспечение выпущено под лицензией MIT.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/mirrors-r3.git
git@api.gitlife.ru:oschina-mirror/mirrors-r3.git
oschina-mirror
mirrors-r3
mirrors-r3
2.0