Git Product home page Git Product logo

Comments (7)

tdv avatar tdv commented on June 14, 2024

Hi.

I think, the sample https://github.com/tdv/nanorpc/tree/master/examples/pure_core will fit quite well for your requirements. There is almost all you need. Consider the piece

auto executor = [srv = std::move(server)]
            (nanorpc::core::type::buffer request) mutable
            {
                std::cout << "Dump. Request: '"
                          << std::string{begin(request), end(request)}
                          << "'" << std::endl;

                auto response = srv.execute(std::move(request));

                std::cout << "Dump. Response: '"
                          << std::string{begin(response), end(response)}
                          << "'" << std::endl;

                return response;
            };

Here you can see how the request and response buffers are exchanging like through another transport. Implement this part respectively your requirements for the transport and you'll get what you need with quite low cost.

Under the hood of the library the same implementation where this part has implemented via tcp having used the boost library.

Good luck!
Hopefully, you'll achieve the goal fast.

Regards.

from nanorpc.

paulocoutinhox avatar paulocoutinhox commented on June 14, 2024

Hi @tdv,

It is near that i want and you have most things implemented.

I made some text about my goal:
paulocoutinhox/cpp-native-mobile#1

Some questions about your sample:

  1. The packer is plain_text because some restrictions/limitations?
    https://github.com/tdv/nanorpc/blob/master/examples/pure_core/src/main.cpp#L22
  2. The param type std::string is the only possible? Can be a custom class like a class Product {}?
  3. Using only the core, i still need the boost dependency?

Thanks.

from nanorpc.

tdv avatar tdv commented on June 14, 2024

Hi @paulocoutinhox

Having read your text, I've completely realized your pain having lack of "reflection" in C++. I had the same. There was not, is not and will not be reflection. A little hope for 23 standard, but I'm not sure. Generally, will not. But if you want, you can make your own reflection. It might be ugly or a bit cute, anyway it's not a native and not out of the box solution. But there are a few approaches how to implement the idea close to desired. I did something similar to reflection earlier on 17th, 11th standard and even more on 03. The older standard than uglier solution.

Having put off the philosophy, in C++ 17 we have interesting feature 'binding'

struct data {
  int field1;
  std::string field2
};

data my_data;

auto [f1, f2] = my_data;

std::cout << f1 << " " << f2 << std::endl;

This feature is the common to crack the type and basic idea in nanorpc. Type packing and unpacking within the library are based on that feature. A restriction is you can't use types with your own user constructors. A little restriction and so big room space for the art.

Answering you question, yes plain_text - is the strategy for packing / unpacking data having included complex types with the nested but limited in usage of user constructors.

You can

struct type1 {
  std::string s;
};

struct type2 {
  int f1;
  std::vector<string> f2;
  std::list<type1> f3;
  type1 f4;
};

And you can't

struct type {
  type() {
     ///...
  }
  int f;
};

Having implemented something with an interface like in plain_text you will get your serialization into desired format and everything else in nanorpc will work with you implementation out of the box.

An example how to deal with complex / user's types you can find here
https://github.com/tdv/nanorpc/tree/master/examples/complex_type

  1. Yep, the core piece is only core, there is no boost need. That is proven by the sample https://github.com/tdv/nanorpc/tree/master/examples/pure_core.

The nanorpc library was a petproject in order to try features of the 17 standards. Before I wrote a library on 11th standard. That is closer to be look like gRPC, but quite hard to understand and supprt (but easy to use). That time there was not anything, only 11th standard. You can consider and forget like a nightmare https://github.com/tdv/mif

In addition you can use a C++ trick and get desirable code like below (from https://github.com/tdv/nanorpc/blob/master/examples/hello_world/client/main.cpp)

        std::string result = client.call("test", std::string{"test"});
        std::cout << "Response from server: " << result << std::endl;

instead of

        auto result = client.call("test", std::string{"test"}).as<std::string>();
        std::cout << "Response from server: " << result << std::endl;

Your choice to an approach...

Everything described above you will find by considering the nanorpc implementation.

Good luck.

Regards.

from nanorpc.

paulocoutinhox avatar paulocoutinhox commented on June 14, 2024

Hi @tdv,

Thanks for explanations.

Im thinking in adopt ProtoBuf or MessagePack for fixed data stream.

So i need send through nanorpc the bytes between platforms. All platform already have protobuf encode/decode functions.

With this, you think that is possible do something generic like this?

#include "product.pb.h"

server.handle("test", [] (std::string const &serialized)
{
    Product deserialized;
    if (!deserialized.ParseFromString( serialized ) )
    {
        std::cout << "ERROR: Unable to deserialize!\n";
        return "";
    }

    std::string serialized;
    if (!s.SerializeToString(&serialized))
    {
        std::cout << "ERROR: Unable to serialize!\n";
        return "";
    }

    return serialized;
});

This is more how nanorpc works.

from nanorpc.

tdv avatar tdv commented on June 14, 2024

Yeah, if you have chosen Protobuf for packing/unpacking a ready to send string has been prepared by nanorpc is will work almost out of the box. In this case you need pick only the transport. In your solution you pack serialized (by nanorpc) buffer into Protobuf message and vice versa to handle result. There will have to be appear only a transport. Pick up a respective / desirable one and your solution is done completely.

Regards.

from nanorpc.

paulocoutinhox avatar paulocoutinhox commented on June 14, 2024

Hi @tdv and thanks again.

More one thing: There is a way to receive custom data on handle method?

Instead of do:

server.handle("test", [] (std::string const &serialized)
{
    [...]
}

I want do:

class Product {};

server.handle("test", [] (Product const &product)
{
    [...]
}
  1. This ^ is related to this example, correct (https://github.com/tdv/nanorpc/tree/master/examples/complex_type)?
  2. There is any limitation?
  3. Any struct can be converted?
  4. Any class can be converted?
  5. What are the limitations that you say on readme (Currently, C++ reflection is not supported out of the box, so this library has some restrictions in using types for function parameters and return values.)?

from nanorpc.

tdv avatar tdv commented on June 14, 2024

Hi, @paulocoutinhox

I mentioned in a few posts above, you can use any type including nested and std containers but you can't use types with user's constructors.

Take a look at

auto &&[f1, f2, f3, f4, f5, f6, f7, f8, f9, f10] = value;

This code allows to get access any field of the structure in order to pack or unpack the one.
As you noticed, there are a structure of the 10 fields binds to 10 independent values. But at the beginning you don't have a certain fields number of the structure and you have to get that missed out info. A structure can contain any fields number. Almost any....
Being sure about certain number of the fields you can handle the fields of the struct / type by the way like below

if constexpr (is_braces_constructible_v<type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type>)
    {
        auto &&[f1, f2, f3, f4, f5, f6, f7, f8, f9, f10] = value;
        return std::make_tuple(f1, f2, f3, f4, f5, f6, f7, f8, f9, f10);
    }
    else if constexpr (is_braces_constructible_v<type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type>)
    {
        auto &&[f1, f2, f3, f4, f5, f6, f7, f8, f9] = value;
        return std::make_tuple(f1, f2, f3, f4, f5, f6, f7, f8, f9);
    }
    else if constexpr (is_braces_constructible_v<type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type>)
    {
        auto &&[f1, f2, f3, f4, f5, f6, f7, f8] = value;
        return std::make_tuple(f1, f2, f3, f4, f5, f6, f7, f8);
    }
    else if constexpr (is_braces_constructible_v<type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type, dummy_type>)
    {
    ....

The issue is how to detect fields count.
An old approach in C++ can help. That's SFINAE. You can detect fields number through picking up certain number from max available for your implementation and getting through all down to zero. On the way you face the needed one. That implemented in the function to_tuple with a helper is_braces_constructible_v. See https://github.com/tdv/nanorpc/blob/master/include/nanorpc/packer/detail/to_tuple.h and https://github.com/tdv/nanorpc/blob/master/include/nanorpc/packer/detail/traits.h
But braces initialization is work well with expected result only in case when a type doesn't have custom constructors. Thus, in the nanorpc library, you can use any type except types with custom constructors.
Now you know about the cause of the restriction.
On the other hand in spite of the restriction you have enough freedom: no macroses in order to add some meta, no code generation, etc, only pure and quite cute code :)
An evil lives here https://github.com/tdv/mif The library if full of templates wrapped in macroces. Very easy to use and get json (and others) marshaling like in Go/Java/etc almost out of the box, rpc like or close to gRPC with a little tax for declaring meta via a few macroces. You can look at https://github.com/tdv/mif/tree/master/examples/microservices only look at :) Very ease and that was the base I used for some project (not petproject only). Easy to develop with 'mif', close to development in Go/Java/Python, all marshaling and everything else I needed for development microservices with REST I had done in the 'mif' library and was using during some years.

Hopefully, I've covered lots of question.
Feel free, ask more if opaque moments left.

Good luck.
Regards.

from nanorpc.

Related Issues (3)

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.