jinq0123 / grpc-lua

The Lua gRPC binding. HTTP/2 based RPC http://grpc.io
BSD 3-Clause "New" or "Revised" License
156 stars 22 forks source link
grpc lua

gRPC-Lua

The Lua gRPC binding.

Dependencies

gRPC-Lua depends on

See doc/conan-graph.html

All these libraries can be installed by conan C/C++ package manager.

Build

Quick Build

  1. Install conan.
  2. Add conan repositories
    • conan remote add remote_bintray_conan-community https://api.bintray.com/conan/conan-community/conan
    • conan remote add remote_bintray_bincrafters https://api.bintray.com/conan/bincrafters/public-conan
    • conan remote add remote_bintray_inexorgame https://api.bintray.com/conan/inexorgame/inexor-conan
    • conan remote add remote_bintray_conan https://api.bintray.com/conan/conan/conan-transit
    • conan remote add remote_bintray_jinq0123 https://api.bintray.com/conan/jinq0123/test
  3. conan create . user/channel --build missing
    • The result grpc_lua.dll/grpc_lua.so is in ~/.conan/data/grpc-lua/0.1/user/channel/package/...

VS solution

See premake/README.md to use premake5 to generate VS solution.

Tutorial

Tutorial shows some codes in the route_guide example.

Define the service

See examples/route_guide/route_guide.proto.

// Interface exported by the server.
service RouteGuide {
  // A simple RPC.
  rpc GetFeature(Point) returns (Feature) {}

  // A server-to-client streaming RPC.
  rpc ListFeatures(Rectangle) returns (stream Feature) {}

  // A client-to-server streaming RPC.
  rpc RecordRoute(stream Point) returns (RouteSummary) {}

  // A Bidirectional streaming RPC.
  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
}
...

Import proto file

For both client and server codes:

local grpc = require("grpc_lua.grpc_lua")
grpc.import_proto_file("route_guide.proto")

No need to generate codes.

Client

See examples/route_guide/route_guide_client.lua.

Create a stub

    local c_channel = grpc.channel("localhost:50051")
    local stub = grcp.service_stub(c_channel, "routeguide.RouteGuide")

Call service method

Server

See examples/route_guide/route_guide_server.lua.

Start server

    local svr = grpc.server()
    svr:add_listening_port("0.0.0.0:50051")
    -- Service implementation is a table.
    local service = require("route_guide_service")
    svr:register_service("routeguide.RouteGuide", service)
    svr:run()

Implement service

Service is a table with the service functions defined in the proto file. The function name must be the same as in the proto file. The function parameters are different for different RPC method types.

  1. Simple RPC: GetFeature()

    --- Simple RPC method.
    -- @tab request
    -- @tparam Replier replier
    function M.GetFeature(request, replier)
        assert("table" == type(request))
        assert("table" == type(replier))
        local name = get_feature_name(request)
        local response = { name = name, location = request }
        replier:reply(response);
    end  -- GetFeature()

    replier can be copied and reply() later.

  2. Server-side streaming RPC: ListFeatures()

    --- Server-to-client streaming method.
    -- @table rectangle
    -- @tparam Writer writer
    function M.ListFeatures(rectangle, writer)
        assert("table" == type(rectangle))
        assert("table" == type(writer))
        ...
        for _, f in ipairs(db.features) do
            local l = f.location
            if l... then
                if not writer.write(f) then
                    print("Failed to write.")
                    break
                end  -- if not writer.write()
            end  -- if l
        end  -- for _, f
        writer.close()
    end  -- ListFeatures()
  3. Client-side streaming RPC: RecordRoute()

    • Should return a reader table:

      --- Client-to-server streaming method.
      -- @tab replier `Replier` object
      -- @treturn table server reader object
      function M.RecordRoute(replier)
          assert("table" == type(replier))
          return require("server_reader.RecordRouteReader"):new(replier, db)
      end  -- RecordRoute()
    • the reader table should optionally have these methods

      • function Reader:on_msg(msg)
      • function Reader:on_error(error_str, status_code)
      • function Reader:on_end()
  4. Bidirectional streaming RPC: RouteChat()

    • Should return a reader table.

      --- Bi-directional streaming method.
      -- @table writer `Writer` object
      -- @treturn table server reader object
      function M.RouteChat(writer)
          assert("table" == type(writer))
          return require("server_reader.RouteChatReader"):new(writer, db)
      end  -- RouteChat()
    • The reader table should optionally have methods as client-side streaming reader.

Example codes

How to run examples

  1. Install dependencies into ~/.conan/data using conan install

    1. Rename examples/conan_install.bat.example to conan_install.bat
    2. Run it.
  2. Copy required exe and dll.

    1. Rename examples/copy_from_conan.bat.example to copy_from_conan.bat
    2. Change variables in copy_from_conan.bat
      • conandata, conan data dir, default ~/.conan/data
      • package names, conan package names for dependencies
        • lua_cpp_package
        • luapbintf_package
        • grpc_lua_package
    3. Run it, which will copy exe and dlls from ~/.conan/data
      • lua-cpp.exe
      • lua-cpp.dll
      • luapbintf.dll
      • grpc_lua.dll
  3. Start lua script

    • helloworld
      • lua-cpp.exe greeter_server.lua
      • lua-cpp.exe greeter_client.lua
    • route_guide
      • lua-cpp.exe route_guide_server.lua
      • lua-cpp.exe route_guide_client.lua

API doc

See doc/ldoc/html/index.html

TODO: Integrate into Unity

Note: If you are using grpc only as client, grpc-tolua is another option.

I think it is easy to integrate grpc-lua into Unity, but I have no time to do this. Work is:

Unity uses Lua library compiled as C. If use lua.exe and lua.lib compiled as C, C++ objects on stack must be destructed correctly on error. See LuaIntf error handling.

Building with Lua51 or LuaJIT library should succeed. LuaPbIntf, which is used to encode and decode protobuf messages, need to be recompiled with Lua51 or LuaJIT.