mif ist ein C++11-Webanwendungsframework, das für die Backend-Microservice-Entwicklung entwickelt wurde. Das Framework nutzt zusätzliche Typ-Metainformationen.
1.5.1
HINWEIS: Der Master-Zweig wird aktiv entwickelt. Verwenden Sie für den Produktionseinsatz die neueste Version.
Zuletzt auf gcc 13.2 getestet
Linux (zuletzt auf Ubuntu 23.10 getestet)
git clone https://github.com/tdv/mif.git
cd mif
./download_third_party.sh
mkdir build
cd build
cmake ..
make
make install
HINWEIS: Unter Ubuntu müssen Sie möglicherweise einige zusätzliche Pakete installieren: liblz4-dev, pkgconf, bison, flex
Sie können versuchen, CMAKE_INSTALL_PREFIX zu verwenden, um das Installationsverzeichnis auszuwählen
Nachdem mif erstellt wurde, können Sie Beispiele erstellen
cd mif /examples/{sample_project}
mkdir build
cd build
cmake ..
make
HINWEIS: Zur Entwicklung Ihrer Bewerbungen können Sie die Bewerbungsvorlage verwenden. Befolgen Sie nach dem Herunterladen des mif -Projekts die Schritte
cd mif /template
mkdir build
cd build
cmake ..
make
Anschließend können Sie diese Vorlage ändern, um Ihre eigene Anwendung zu erstellen. Darüber hinaus können Sie die aus der Vorlage erstellten Beispiele verwenden. Die Beispiele sind vollständig ausgefüllt und verfügen über ein Skript zum Erstellen selbst. Alle befinden sich im Ordner _docs. Eine ausführliche Dokumentation der Beispiele finden Sie im Wiki.
Server:
cd mif /exammples/{sample_project}/bin
./{sample_project}_server
Kunde:
cd mif /exammples/{sample_project}/bin
./{sample_project}_client
Bitte verwenden Sie --help, um weitere Informationen zum Ausführen eines Beispiels zu erhalten
Quellcode
Beschreibung
Das Beispiel demonstriert die Funktionsweise des einfachen HTTP-Echoservers. HTTP-Echo-Server
// 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);
}
Prüfen
curl -iv -X POST " http://localhost:55555/ " -d ' Test data '
Quellcode
Beschreibung
Das Beispiel demonstriert die Arbeit des HTTP-Servers mit Dual-Schnittstelle zur Verarbeitung von rohen HTTP-Anfragen und mif RPC per HTTP. Mehr erfahren Sie im Kapitel „Webservice. Weiteres“
Quellcode
Beschreibung
Das Beispiel „Hello World“ demonstriert eine einfache Client-Server-Anwendung mit schnittstellenbasiertem RPC-Marshalling und TCP-Kommunikation unter Verwendung von boost.archives für die Datenserialisierung
Grundlegende Schritte zum Erstellen einer Client-Server-Anwendung mit RPC
Gemeinsame Schnittstelle
// 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
Metainformationen der gemeinsamen Schnittstelle
// 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)
Implementierung der Serverschnittstelle
...
// 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
)
Serveranwendung
// 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);
}
Client-Anwendung
// 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);
}
Quellcode
Beschreibung
Dieses Beispiel ist dasselbe wie „Hello World“. Der Unterschied besteht darin, Remote-Methoden mit benutzerdefinierten Datenstrukturen als Parameter aufzurufen und einen Wert zurückzugeben. Die Projektstruktur ist die gleiche wie im vorherigen Projektbeispiel, wir fügen lediglich die Definition benutzerdefinierter Datenstrukturen und Metainformationen hinzu.
Benutzerdatenstrukturen
// 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
Metainformationen
// 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)
Quellcode
Beschreibung
Im Vergleich zu den vorherigen Beispielen kommt hier die Schnittstellenvererbung hinzu. In der Implementierung können Sie eine Schnittstelle abfragen, die außerhalb der Hierarchie liegt.
Quellcode
Beschreibung
Das Beispiel „Visitor“ demonstriert den Mechanismus von Remote-Callbacks für Schnittstellenmethoden. Dies kann als Ausgangspunkt für Publish/Subscribe-basierte Anwendungen verwendet werden.
Quellcode
Beschreibung
Das Beispiel demonstriert die Json-API (CRUD-Operationen) auf einem HTTP-Server.
Prüfen
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 "
Quellcode
Beschreibung
Das Beispiel demonstriert die Kommunikation zwischen zwei Microservices (das Beispiel ist eine leistungsfähigere Version von http crud). Prüfen
./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 "
Quellcode
Beschreibung
Das Beispiel demonstriert den Mechanismus der C++-Datenstrukturreflexion. Dies kann als Ausgangspunkt für die Erstellung von Anwendungen mit Serialisierung, ORM und REST-API verwendet werden.