Как стать автором
Обновить

Ускорение серверной разработки

Уровень сложностиПростой
Время на прочтение3 мин
Количество просмотров2.1K

Всем привет! Пишу свою первую статью - не судите строго :-)

Сегодня хочу рассказать вам о своём проекте, а точнее показать его в деле. Надеюсь, вам будет интересно!

Введение

Netter - инструмент для быстрого и лёгкого поднятия серверов. Он поддерживает следующий функционал:

  • Запуск HTTP / HTTPS серверов;

  • Тонкая настройка логики обработки на каждый маршрут с помощью язык описания маршрутов (RDL). Используется собственный интерпретатор;

  • Поддержка кастомных плагинов для их последующего использования в RDL. Плагины пишутся на Rust с использованием специального крейта для облегчения разработки

Проект создан для разработчиков, которым надоело писать большой код для запуска простых/средних по сложности серверов

Route Definition Language

Route Definition Language (RDL) - интерпретируемый язык для описания маршрутов и серверной логики.

Синтаксис

config {
    type = "http"; // тип сервера
    host = "127.0.0.1"; // ip адрес, по которому будет доступен сервер
    port = 8080; // порт сервера
}; // после блоков ';' обязательна

import "absolute/path/to/file.dll" as plugin_alias;
// absolute/path/to/file.dll - абсолютный путь до динамической библиотеки .dll или .so
// plugin_alias - алиас для плагина. Будет использован для доступа к функциям из плагина

global_error_handler(e) { // глоабльный обработчик ошибок.
                          // здесь будут все ошибки, которые перехватил '?',
                          // но локальный обработчик не был указан
    Response.body("Global error: "+ e);
    Response.status(500);
    Response.send();
};

route "/" GET { // ждём запросы на "/" по запросу GET
    val body = Request.body()?; // получаем тело запроса
    // '?' перехватывает ошибки
    if (body == "empty") {
        Response.body("Body is empty!"); // ставим тело ответа
        Response.status(400); // ставим статус ответа
        Response.send(); // отправляем ответ
    };
    Response.body(body + "!empty"); // конкатенация строк
    Response.send(); // 200 OK
} onError(e) { // локальный обработчик ошибок. Если Request.body()? завершится ошибкой,
               // кодд перейдёт сюда
               // локальные обработчики имеют приоритет над глобальными
    Response.status(500);
    Response.body(e); // ставим тело ответа с текстом ошибки
    Response.send();
};

Ключевые слова

Язык имеет следующие ключевые слова:

  • route - объявление маршрута;

  • GET, POST, PUT и т.д. - тип запроса;

  • global_error_handler - объявление глобального обработчика ошибок;

  • onError - объявление локального обработчика

Более подробно с документацией языка (объекты, функции, ключевые слова, обработчики ошибок...) можно в репозитории.

Обработка ошибок

Обработка ошибок - ключевой элемент написания кода. Язык предоставляет возможность обработать ошибки:

  • Знак ? перехватывает все ошибки, которые может вернуть функция;

  • !! игнорирует ошибки, но код завершится паникой, если ошибка всё же будет.

Существует два обработчика ошибок: локальный и глобальный. Локальный всегда имеет приоритет над глобальным, т.е. все ошибки, перехваченные ?, перейдут в локальный обработчик, если он есть, иначе в глобальный.

Плагины

Netter предоставляет крейт netter_plugger, который поможет вам в создании более сложных функций, которые RDL сделать не позволит.

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

use netter_plugger::{netter_plugin, generate_dispatch_func};

generate_dispatch_func!();

#[netter_plugin]
fn something(
    path: String,
) -> Result<String, String> {
    let result = "heey".to_string();
    if path == "error" {
        Err("err from plugin".to_string())
    } else {
        Ok(format!("{result}: {path}"))
    }
}
  • Макрос generate_dispatch_func!(); обязательно должен находиться наверху файла. Он инициализирует входную точку в плагин

  • Атрибут #[netter_plugin] помечает функции вызываемыми из RDL

Как это работает?

Весь ваш код из функции переводится в C-совместимый код, так что готовьтесь к unsafe extern "C", хотя в базовых случаях проблем быть не должно.

После импорта вашей динамической библиотеки (которую вы ранее собрали из плагина на Rust), интерпретатор ищет и открывает её, выполняет код из либы и возвращает результат функции обратно в RDL.

Служба (демон)

Служба (или демон) помогает запускать сервера в фоне и улучшить их устойчивость.

Всё общение между клиентом (CLI) и сервисом происходит по протоколу IPC. Каждый запуск демона / службы логируется в новый файл (т.е. создаётся новый файл логов, в который записываются все логи).

Развитие проекта

Главное направление, которое я стараюсь сохранять - легкость в освоении и довольно высокая скорость разработки. Со временем проект будет постоянно развиваться в соответствии с моим виденьем и вашими запросами

Планы по развитию:

  • Графический UI на десктоп и мобильные устройства для визуализации разработки, упрощения использования инструмента и ускорения описания серверной логики;

  • Поддержка режима обратного прокси;

  • Создание балансировки нагрузок;

  • Реализация других протоколов;

  • Пакетный менеджер для плагинов (динамических библиотек).

Заключение

Это мой первый крупный проект. Не судите строго :-)

Спасибо всем, кто прочитал "это", делится своим мнением о проекте, его проблемах, вносит вклад в его развитие!

Github

Теги:
Хабы:
+1
Комментарии9

Публикации

Работа

Rust разработчик
4 вакансии

Ближайшие события