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