mif est un framework d'application Web C++11 conçu pour le développement de microservices backend. Le framework utilise des méta-informations de type supplémentaires.
1.5.1
REMARQUE : La branche principale est activement développée, utilisez la dernière version pour une utilisation en production.
Dernièrement testé sur gcc 13.2
Linux (dernièrement testé sur 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
REMARQUE : Dans Ubuntu, vous devrez peut-être installer des packages supplémentaires : liblz4-dev, pkgconf, bison, flex
Vous pouvez essayer d'utiliser CMAKE_INSTALL_PREFIX pour sélectionner le répertoire d'installation
Une fois mif construit, vous pouvez créer des exemples
cd mif /examples/{sample_project}
mkdir build
cd build
cmake ..
make
REMARQUE : Pour développer vos applications, vous pouvez utiliser le modèle d'application. Après avoir téléchargé le projet mif , suivez les étapes
cd mif /template
mkdir build
cd build
cmake ..
make
Après cela, vous pouvez modifier ce modèle pour créer votre propre application. De plus, vous pouvez utiliser les exemples réalisés à partir du modèle. Les exemples sont entièrement complétés et disposent d'un script pour se construire lui-même. Tous se trouvent dans le dossier _docs. Vous pouvez trouver une documentation détaillée des exemples dans le wiki.
Serveur:
cd mif /exammples/{sample_project}/bin
./{sample_project}_server
Client:
cd mif /exammples/{sample_project}/bin
./{sample_project}_client
Veuillez utiliser --help pour obtenir plus d'informations sur l'exécution d'un exemple
Code source
Description
L'exemple démontre le travail du simple serveur d'écho HTTP. Serveur d'écho 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);
}
Test
curl -iv -X POST " http://localhost:55555/ " -d ' Test data '
Code source
Description
L'exemple démontre le travail du serveur HTTP avec double interface pour traiter les requêtes HTTP brutes et mif RPC par HTTP. Vous pouvez en voir plus dans le chapitre "Service Web. Supplémentaire"
Code source
Description
L'exemple « Hello World » illustre une application client-serveur de base avec le marshaling RPC basé sur l'interface et la communication TCP avec l'utilisation de boost.archives pour la sérialisation des données.
Étapes de base pour créer une application client-serveur avec RPC
Interface commune
// 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
Méta-informations de l'interface commune
// 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)
Implémentation de l'interface serveur
...
// 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
)
Application serveur
// 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);
}
Demande client
// 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);
}
Code source
Description
Cet exemple est le même que « Hello World ». La différence réside dans l'appel de méthodes distantes avec des structures de données définies par l'utilisateur comme paramètres et dans le renvoi d'une valeur. La structure du projet est la même que dans l'exemple de projet précédent, nous ajoutons uniquement la définition des structures de données et des méta-informations définies par l'utilisateur.
Structures de données utilisateur
// 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
Méta-informations
// 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)
Code source
Description
Par rapport aux exemples précédents, celui-ci ajoute l'héritage d'interface. Dans l'implémentation, vous pouvez interroger une interface hors hiérarchie.
Code source
Description
L'exemple « Visiteur » démontre le mécanisme de rappels à distance pour les méthodes d'interface. Cela peut être utilisé comme point de départ pour les applications basées sur la publication/l'abonnement.
Code source
Description
L'exemple illustre l'API Json (opérations CRUD) sur le serveur HTTP.
Test
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 "
Code source
Description
L'exemple montre la communication entre deux microservices (l'exemple est une version plus puissante de http crud). Test
./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 "
Code source
Description
L'exemple montre le mécanisme de réflexion des structures de données C++. Cela peut être utilisé comme point de départ pour créer une application avec la sérialisation, l'ORM et l'API REST.