mif — это платформа веб-приложений C++11, предназначенная для разработки серверных микросервисов. Фреймворк использует дополнительную метаинформацию о типах.
1.5.1
ПРИМЕЧАНИЕ. Основная ветка активно развивается, для производственных целей используйте последнюю версию.
Последнее тестирование на gcc 13.2.
Linux (последний раз тестировался на Ubuntu 23.10)
git clone https://github.com/tdv/mif.git
cd mif
./download_third_party.sh
mkdir build
cd build
cmake ..
make
make install
ПРИМЕЧАНИЕ. В Ubuntu вам, возможно, придется установить некоторые дополнительные пакеты: liblz4-dev, pkgconf, bison, flex.
Вы можете попробовать использовать CMAKE_INSTALL_PREFIX для выбора каталога установки.
После сборки mif вы можете создавать примеры.
cd mif /examples/{sample_project}
mkdir build
cd build
cmake ..
make
ПРИМЕЧАНИЕ. Для разработки приложений вы можете использовать шаблон приложения. После загрузки проекта mif выполните следующие действия.
cd mif /template
mkdir build
cd build
cmake ..
make
После этого вы можете изменить этот шаблон, чтобы создать собственное приложение. Кроме того, вы можете использовать примеры, сделанные из шаблона. Примеры полностью завершены и имеют скрипт для самой сборки. Все они находятся в папке _docs. Подробную документацию примеров вы можете найти в вики.
Сервер:
cd mif /exammples/{sample_project}/bin
./{sample_project}_server
Клиент:
cd mif /exammples/{sample_project}/bin
./{sample_project}_client
Используйте --help, чтобы получить дополнительную информацию о запуске примера.
Исходный код
Описание
В примере демонстрируется работа простого HTTP-эхо-сервера. HTTP-эхо-сервер
// mif
# include < mif /application/http_server.h >
# include < mif /common/log.h >
# include < mif /net/http/constants.h >
class Application
: public mif ::Application::HttpServer
{
public:
using HttpServer::HttpServer;
private:
// mif .Application.HttpServer
virtual void Init ( mif ::Net::Http::ServerHandlers &handlers) override final
{
handlers[ " / " ] = [] ( mif ::Net::Http::IInputPack const &request,
mif ::Net::Http::IOutputPack &response)
{
auto data = request. GetData ();
mif _LOG (Info) << " Process request " " << request. GetPath () << request. GetQuery () << " "t Data: "
<< (data. empty () ? std::string{ " null " } : std::string{ std::begin (data), std::end (data)});
response. SetCode ( mif ::Net::Http::Code::Ok);
response. SetHeader ( mif ::Net::Http::Constants::Header::Connection::Value,
mif ::Net::Http::Constants::Value::Connection::Close::Value);
response. SetData ( std::move (data));
};
}
};
int main ( int argc, char const **argv)
{
return mif ::Application::Run<Application>(argc, argv);
}
Тест
curl -iv -X POST " http://localhost:55555/ " -d ' Test data '
Исходный код
Описание
В примере демонстрируется работа HTTP-сервера с двойным интерфейсом для обработки необработанных HTTP-запросов и mif RPC по HTTP. Подробнее вы можете посмотреть в разделе «Веб-сервис. Дополнительно»
Исходный код
Описание
Пример «Hello World» демонстрирует базовое клиент-серверное приложение с маршалингом RPC на основе интерфейса и связью TCP с использованием boost.archives для сериализации данных.
Основные шаги по созданию клиент-серверного приложения с помощью RPC
Общий интерфейс
// STD
# include < string >
// mif
# include < mif /service/iservice.h >
namespace Service
{
struct IHelloWorld
: public mif ::Service::Inherit< mif ::Service::IService>
{
virtual void AddWord (std::string const &word) = 0;
virtual std::string GetText () const = 0;
virtual void Clean () = 0;
};
} // namespace Service
Метаинформация общего интерфейса
// STD
# include < string >
// mif
# include < mif /remote/ps.h >
// THIS
# include " common/interface/ihello_world.h "
namespace Service
{
namespace Meta
{
using namespace ::Service ;
mif _REMOTE_PS_BEGIN (IHelloWorld)
mif _REMOTE_METHOD (AddWord)
mif _REMOTE_METHOD (GetText)
mif _REMOTE_METHOD (Clean)
mif _REMOTE_PS_END ()
} // namespace Meta
} // namespace Service
mif _REMOTE_REGISTER_PS (Service::Meta::IHelloWorld)
Реализация серверного интерфейса
...
// mif
# include < mif /service/creator.h >
// THIS
# include " common/id/service.h "
# include " common/interface/ihello_world.h "
namespace Service
{
namespace Detail
{
namespace
{
class HelloWorld
: public IHelloWorld
{
public:
...
private:
...
// IHelloWorld
virtual void AddWord (std::string const &word) override final
{
...
}
virtual std::string GetText () const override final
{
...
}
virtual void Clean () override final
{
...
}
};
} // namespace
} // namespace Detail
} // namespace Service
mif _SERVICE_CREATOR
(
::Service::Id::HelloWorld,
::Service::Detail::HelloWorld
)
Серверное приложение
// mif
# include < mif /application/tcp_service.h >
// COMMON
# include " common/id/service.h "
# include " common/ps/ihello_world.h "
class Application
: public mif ::Application::TcpService
{
public:
using TcpService::TcpService;
private:
// mif .Application.TcpService
virtual void Init ( mif ::Service::FactoryPtr factory) override final
{
factory-> AddClass <Service::Id::HelloWorld>();
}
};
int main ( int argc, char const **argv)
{
return mif ::Application::Run<Application>(argc, argv);
}
Клиентское приложение
// mif
# include < mif /application/tcp_service_client.h >
# include < mif /common/log.h >
// COMMON
# include " common/ps/ihello_world.h "
class Application
: public mif ::Application::TcpServiceClient
{
public:
using TcpServiceClient::TcpServiceClient;
private:
// mif .Application.TcpServiceClient
virtual void Init ( mif ::Service::IFactoryPtr factory) override final
{
auto service = factory-> Create <Service::IHelloWorld>( " HelloWorld " );
mif _LOG (Info) << " Add words. " ;
service-> AddWord ( " Hello " );
service-> AddWord ( " World " );
service-> AddWord ( " !!! " );
mif _LOG (Info) << " Result from server: " " << service-> GetText () << " " " ;
mif _LOG (Info) << " Clean. " ;
service-> Clean ();
mif _LOG (Info) << " Result from server: " " << service-> GetText () << " " " ;
}
};
int main ( int argc, char const **argv)
{
return mif ::Application::Run<Application>(argc, argv);
}
Исходный код
Описание
Этот пример аналогичен «Hello World». Разница заключается в вызове удаленных методов с определяемыми пользователем структурами данных в качестве параметров и возврате значения. Структура проекта такая же, как и в предыдущем примере проекта, мы добавляем только определение пользовательских структур данных и метаинформации.
Структуры пользовательских данных
// STD
# include < cstdint >
# include < map >
# include < string >
namespace Service
{
namespace Data
{
using ID = std::string;
struct Human
{
std::string name;
std::string lastName;
std:: uint32_t age = 0 ;
};
enum class Position
{
Unknown,
Developer,
Manager
};
struct Employee
: public Human
{
Position position = Position::Unknown;
};
using Employees = std::map<ID, Employee>;
} // namespace Data
} // namespace Service
Метаинформация
// mif
# include < mif /reflection/reflect_type.h >
// THIS
# include " common/data/data.h "
namespace Service
{
namespace Data
{
namespace Meta
{
mif _REFLECT_BEGIN (Human)
mif _REFLECT_FIELD (name)
mif _REFLECT_FIELD (lastName)
mif _REFLECT_FIELD (age)
mif _REFLECT_END ()
mif _REFLECT_BEGIN (Position)
mif _REFLECT_FIELD (Unknown)
mif _REFLECT_FIELD (Developer)
mif _REFLECT_FIELD (Manager)
mif _REFLECT_END ()
mif _REFLECT_BEGIN (Employee, Human)
mif _REFLECT_FIELD (position)
mif _REFLECT_END ()
} // namespace Meta
} // namespace Data
} // namespace Service
mif _REGISTER_REFLECTED_TYPE (::Service::Data::Meta::Human)
mif _REGISTER_REFLECTED_TYPE(::Service::Data::Meta::Position)
mif _REGISTER_REFLECTED_TYPE(::Service::Data::Meta::Employee)
Исходный код
Описание
По сравнению с предыдущими примерами в этом добавлено наследование интерфейса. В реализации вы можете запросить интерфейс, который находится вне иерархии.
Исходный код
Описание
Пример «Посетитель» демонстрирует механизм удаленных обратных вызовов для методов интерфейса. Это можно использовать в качестве отправной точки для приложений на основе публикации/подписки.
Исходный код
Описание
В примере демонстрируется API Json (операции CRUD) на HTTP-сервере.
Тест
curl -i -X POST " http://localhost:55555/employee/create " -d ' {"name":"Ivan", "lastName":"Ivanov","age":33,"email":"[email protected]","position":"Developer","rate":200000.00} '
curl -i " http://localhost:55555/employee/read?id=1 "
curl -i " http://localhost:55555/employee/update?id=1 " -d ' {"name":"Ivan", "lastName":"Ivanov","age":33,"email":"[email protected]","position":"Developer","rate":220000.00} '
curl -i " http://localhost:55555/employee/list?limit=2&offset=0 "
curl -i " http://localhost:55555/employee/delete?id=1 "
Исходный код
Описание
В примере демонстрируется взаимодействие между двумя микросервисами (пример представляет собой более мощную версию http crud). Тест
./storage —config=storage.xml
./service --config=service.xml
curl -i -X POST " http://localhost:55555/employee/create " -d ' {"name":"Ivan", "lastName":"Ivanov","age":33,"email":"[email protected]","position":"Developer","rate":200000.00} '
curl -i " http://localhost:55555/employee/read?id=1 "
curl -i " http://localhost:55555/employee/update?id=1 " -d ' {"name":"Ivan", "lastName":"Ivanov","age":33,"email":"[email protected]","position":"Developer","rate":220000.00} '
curl -i " http://localhost:55555/employee/list?limit=2&offset=0 "
curl -i " http://localhost:55555/employee/delete?id=1 "
Исходный код
Описание
В примере демонстрируется механизм отражения структуры данных C++. Это можно использовать в качестве отправной точки для создания приложения с сериализацией, ORM и REST API.