mif es un marco de aplicación web C++11 diseñado para el desarrollo de microservicios backend. El marco utiliza metainformación de tipo adicional.
1.5.1
NOTA: La rama master se desarrolla activamente; utilice la última versión para uso en producción.
Probado por última vez en gcc 13.2
Linux (últimamente probado en 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
NOTA: En Ubuntu es posible que tengas que instalar algunos paquetes adicionales: liblz4-dev, pkgconf, bison, flex
Puede intentar usar CMAKE_INSTALL_PREFIX para seleccionar el directorio de instalación
Una vez creado mif , puede crear ejemplos.
cd mif /examples/{sample_project}
mkdir build
cd build
cmake ..
make
NOTA: Para desarrollar sus aplicaciones, puede utilizar la plantilla de aplicación. Después de descargar el proyecto mif , siga los pasos.
cd mif /template
mkdir build
cd build
cmake ..
make
Después de eso puedes cambiar esta plantilla para crear tu propia aplicación. Además, puede utilizar los ejemplos creados a partir de la plantilla. Los ejemplos están completamente completos y tienen un script para construirlos. Todos ellos están en la carpeta _docs. Puede encontrar documentación detallada de los ejemplos en la wiki.
Servidor:
cd mif /exammples/{sample_project}/bin
./{sample_project}_server
Cliente:
cd mif /exammples/{sample_project}/bin
./{sample_project}_client
Utilice --help para obtener más información sobre cómo ejecutar un ejemplo
código fuente
Descripción
El ejemplo demuestra el trabajo del servidor de eco HTTP simple. servidor de eco 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);
}
Prueba
curl -iv -X POST " http://localhost:55555/ " -d ' Test data '
código fuente
Descripción
El ejemplo demuestra el trabajo del servidor HTTP con interfaz dual para procesar solicitudes HTTP sin procesar y mif RPC por HTTP. Más puedes ver en el capítulo "Servicio web. Adicional"
código fuente
Descripción
El ejemplo "Hello World" demuestra una aplicación cliente-servidor básica con serialización RPC basada en interfaz y comunicación TCP con el uso de boost.archives para la serialización de datos.
Pasos básicos para construir una aplicación cliente-servidor con RPC
Interfaz común
// 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
Metainformación de la interfaz común
// 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)
Implementación de la interfaz del servidor
...
// 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
)
aplicación de servidor
// 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);
}
Solicitud de cliente
// 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);
}
código fuente
Descripción
Este ejemplo es el mismo que "Hola mundo". La diferencia está en llamar a métodos remotos con estructuras de datos definidas por el usuario como parámetros y devolver un valor. La estructura del proyecto es la misma que en el ejemplo de proyecto anterior, solo agregamos la definición de estructuras de datos y metainformación definidas por el usuario.
Estructuras de datos de usuario
// 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
Metainformación
// 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)
código fuente
Descripción
En comparación con los ejemplos anteriores, este agrega la herencia de interfaz. En la implementación, puede consultar una interfaz que esté fuera de jerarquía.
código fuente
Descripción
El ejemplo "Visitante" demuestra el mecanismo de devoluciones de llamadas remotas para métodos de interfaz. Esto se puede utilizar como punto de partida para aplicaciones basadas en publicación/suscripción.
código fuente
Descripción
El ejemplo demuestra la API Json (operaciones CRUD) en el servidor HTTP.
Prueba
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ódigo fuente
Descripción
El ejemplo demuestra la comunicación entre dos microservicios (el ejemplo es una versión más potente de http crud). Prueba
./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ódigo fuente
Descripción
El ejemplo demuestra el mecanismo de reflexión de la estructura de datos de C++. Esto se puede utilizar como punto de partida para crear aplicaciones con serialización, ORM y API REST.