Всем привет! Пишу свою первую статью - не судите строго :-)
Сегодня хочу рассказать вам о своём проекте, а точнее показать его в деле. Надеюсь, вам будет интересно!
Введение
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 на десктоп и мобильные устройства для визуализации разработки, упрощения использования инструмента и ускорения описания серверной логики;
Поддержка режима обратного прокси;
Создание балансировки нагрузок;
Реализация других протоколов;
Пакетный менеджер для плагинов (динамических библиотек).
Заключение
Это мой первый крупный проект. Не судите строго :-)
Спасибо всем, кто прочитал "это", делится своим мнением о проекте, его проблемах, вносит вклад в его развитие!