Giter Site home page Giter Site logo

tdv / mif Goto Github PK

View Code? Open in Web Editor NEW
46.0 8.0 9.0 1.14 MB

MIF is a C++11 web-application framework designed for the backend micro-service development

License: MIT License

CMake 2.97% C++ 96.95% Shell 0.08%
cpp webservice rpc-framework web-framework web-backend reflection modern-cpp microservice-framework web-app web-application-framework

mif's Introduction

MIF - C++11 MetaInfo Framework

MIF is a C++11 web-application framework designed for the backend micro-service development. The framework makes use of additional type meta-information.

Version

1.5.1

NOTE: The master branch is actively developed, use latest release for production use.

Features:

  • Network classes for the easy creation of simple web services
  • Interface-based RPC marshalling with the callback support
  • Reflection for c++ data structures with the inheritance support
  • Json, Xml serialization and the ability to use boost archives
  • Database support (Implemented for PostgreSQL)

Compiler

Lastly tested on gcc 13.2

OS

Linux (Lastly tested on Ubuntu 23.10)

Dependencies

  • Boost
  • zlib
  • libpq

Build and install

git clone https://github.com/tdv/mif.git  
cd mif  
./download_third_party.sh  
mkdir build  
cd build  
cmake ..  
make  
make install  

NOTE: In Ubuntu you might have to install some additional packages: liblz4-dev, pkgconf, bison, flex

You can try using CMAKE_INSTALL_PREFIX to select the installation directory

Build examples

After mif is built, you can build examples

cd mif/examples/{sample_project}
mkdir build  
cd build  
cmake ..  
make  

NOTE: To develop your applications, you can use the application template. After downloading the MIF project, follow the steps

cd mif/template
mkdir build  
cd build  
cmake ..  
make  

After that you can change this template to create your own application. In addition, you can use the examples doned from the template. Examples are fully completed and have a script for build itself. All of them are in the _docs folder. You can find detailed documentation of the examples in the wiki.

Run examples

Server:

cd mif/exammples/{sample_project}/bin  
./{sample_project}_server  

Client:

cd mif/exammples/{sample_project}/bin  
./{sample_project}_client  

Please use --help to get more information about runing an example

Examples

HTTP Echo Server

Source code
Description
The example demonstrates the work of the simple HTTP echo server. 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);
}

Test

curl -iv -X POST "http://localhost:55555/" -d 'Test data'

HTTP

Source code
Description
The example demonstrates the work of the HTTP server with dual interface for processing raw HTTP requests and MIF RPC by HTTP. More you can see in the chapter "Web service. Additional"

RPC. Hello World

Source code
Description
The "Hello World" example demonstrates a basic client-server application with the interface-based RPC marshaling and TCP communication with using boost.archives for data serialization

Basic steps for building a client-server application with RPC

  • define interface
  • add meta-information about interface and methods
  • create a data flow processing chain from a set of handler elements or use one of the prepared applications templates
  • implement interface on the server side and create a server application
  • create communication channel and proxy objects on the client side and create a client application

Common interface

// 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

Common interface meta-information

// 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)

Server interface implementation

...
// 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
)

Server application

// 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 application

// 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);
}

Complex Type

Source code
Description
This example is the same as "Hello World". The difference is in calling remote methods with user-defined data structures as parameters and returning a value. The project structure is the same as in the previous project example, we only add the definition of user-defined data structures and meta-information.

User data structs

// 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

Meta-information

// 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)

Inheritance

Source code
Description
Compared to the previous examples this one adds the inteface inheritance. In the implementation you can query an interface which is out of hierarchy.

Visitor

Source code
Description
The "Visitor" example demonstrates the mechanism of remote callbacks for interface methods. This can be used as a starting point for publish / subscribe based applications.

HTTP CRUD

Source code
Description
The example demonstrates the Json API (CRUD operations) on HTTP server.

Test

  • run PostgreSQL
  • apply DB schema from folder db
  • modify config/config.xml
  • run http_crud server with parameter --config (in folder 'bin' execute ./http_crud --config=../config/config.xml)
  • execute commands
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"

Microservices

Source code
Description
The example demonstrates communication between two microservices (the example is more powerful version of http crud). Test

  • run PostgreSQL
  • apply DB schema from folder db
  • modify config/storage.xml
  • run components
./storage —config=storage.xml
./service --config=service.xml
  • execute commands
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"

Reflection

Source code
Description
The example demonstrates the mechanism of C++ data struct reflection. This can be used as a starting point for building application with serialization, ORM and REST API.

mif's People

Contributors

paceholder avatar prongq avatar tdv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mif's Issues

Enum serialization

Добавить возможность сериализации перечислений вида
enum class MyEnum : std::uint32_t
{
};

Support for dynamic modules

Реализовать создание компонент в виде динамически загружаемых библиотек.
Хорошо бы иметь возможность, при которой, один и тот же код может быть собран с виде компонент, разделенных по динамически загружаемым библиотекам, и при необходимости иметь возможность собрать все эти компоненты в виде одного исполняемого модуля.
Хорошо бы иметь процессы-суррогаты, в которых можно будет загружать готовые компоненты, реализованные в виде отдельных динамически загружаемых модулей, для которых бы процессы-суррогаты служили бы контейнерами для исполнения.

Support of pointers and references in interface methods

Реализовать возможность передачи не константных указателей и ссылок в методы интерфейсов.
При модификации объектов, переданных по не константным ссылкам / указателям, на одной стороне, например, на стороне сервера, на стороне клиента эти изменения должны быть доступны. Т.е. реализовать поддержку "out" параметров из методов для не константных ссылок / указателей, а так же возможность возвращать из методов указатели и ссылки.

Reflection

Добавить возможность перебирать поля структур (reflection) для реализации сериализации, ORM, загрузки конфигурационных файлов, реализации REST API и т.д.

Structs serialization based on boost.serialization

Для вызова удаленных методов (де)сериализация реализована на boost.serialization, но нет поддержки (де)сериализации пользовательских типов. Хотелось бы иметь возможность передавать структуры в качестве аргументов удаленных методов или их возвращаемых результатов. Для этого нужно реализовать обобщенный механизм (де)сериализации пользовательских типов данных (структур) на boost.serialization.

Http server params

Добавить возможность передавать параметры при создании http сервера, например, такие, как ограничения на размер буфера, размер заголовков, название (имя) сервера и т.д. Параметры можно передавать, как для http сервера, так и для http-обертки, которая используется в качестве транспорта для удаленного вызова методов.

JSON serialization

Добавить возможность (де)сериализации в json, например, с помощью библиотеки jsoncpp

Exception handling

Пробрасывать исключения между процессами клиента и сервера.
Исключения должны быть как минимум 2х типов:

  • системные (ошибка связи, упаковки и т.д.)
  • ошибки бизнес логики (кода методов прокси и стабов)

Logging

Логирование на базе boost.log

HTTP transport

Реализовать взаимодействие клиента с сервером по протоколу HTTP, например, на базе библиотеки libevent2

Interface inheritance

Хотелось бы иметь возможность наследования интерфейсов. Наследование может быть множественным. Так же хотелось бы иметь возможность создания объектов из уже готовых реализаций интерфейсов.
В рамках этой работы так же должна появиться возможность возвращать интерйсы из методов и принимать их в качестве аргуметов.

Python integration

Добавить возможность обращаться к объектам на C++ из Python

Run in daemon mode

Нужна возможность запуска процессов в режиме демона.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.