Rust-Rpcx rs: rpcx-rs RPC — A RPC library for Rust for developing microservices in easy and simple way.

rpcx-rs

Build Status Crate API

Rust library for rpcx rpc/microservice framework.

Use the simplest style to explore Rust function as cross-platform rpc services.

If you can write Rust functions, you can write rpc services. It is so easy.

see all exampes: rpcx-rs-examples.

Roadmap

0.1.x

protocol and client/server lib.

  • Protocol
  • Client (call synchronous/asynchronous)
  • support JSON, MessagePack and Protobuf
  • Service implementation

0.2.x

  • Service discovery
    • static multiple peers
    • etcd
    • consul
  • service governance
  • Select Mode
    • RandomSelect,
    • RoundRobin
    • WeightedRoundRobin
    • WeightedICMP
    • ConsistentHash
    • Closest
    • Custiomized
  • Faile Mode
    • Failover
    • Failfast
    • Failtry

0.3.x

  • plugins
  • document
  • unit tests and integration tests
  • other features like implementation in Go

Usage

Add this to your Cargo.toml:

[dependencies]
rpcx = "0.2.0"

Example

Write the Argument and the Reply

First you should write the argument and the reply. They are used by rpc services and clients.

use std::error::Error as StdError;

use rmp_serde as rmps; 
use serde::{Deserialize, Serialize};

use rpcx_derive::*;
use rpcx_protocol::{Error, ErrorKind, Result, RpcxParam, SerializeType};

#[derive(RpcxParam, Default, Debug, Copy, Clone, Serialize, Deserialize)]
pub struct ArithAddArgs {
    #[serde(rename = "A")]
    pub a: u64,
    #[serde(rename = "B")]
    pub b: u64,
}
#[derive(RpcxParam, Default, Debug, Copy, Clone, Serialize, Deserialize)]
pub struct ArithAddReply {
    #[serde(rename = "C")]
    pub c: u64,
}

You must add RpcxParamSerializeDeserialize and Default traits in derive. Rpcx can add hepler methods for serialization.

If not, you need to implement RpcxParam and Default mannually.

Here we defined ArithAddArgs as the argument type and ArithAddReply as the reply type.

Implement the server

use mul_model::{ArithAddArgs, ArithAddReply};
use rpcx::*;

fn add(args: ArithAddArgs) -> ArithAddReply {
    ArithAddReply { c: args.a + args.b }
}

fn mul(args: ArithAddArgs) -> ArithAddReply {
    ArithAddReply { c: args.a * args.b }
}

fn main() {
    let mut rpc_server = Server::new("127.0.0.1:8972".to_owned());
    register_func!(
        rpc_server,
        "Arith",
        "Add",
        add,
        ArithAddArgs,
        ArithAddReply
    );

    register_func!(
        rpc_server,
        "Arith",
        "Mul",
        mul,
        ArithAddArgs,
        ArithAddReply
    );

    rpc_server.start().unwrap();
}

Here we implement two services: add and mul. And we use register_func! macro to register them with their expored names(service_path and service_method). Clients can use the name to access them.

Implement client

Here we use one client to access Arith.Mul service in a loop.

use std::collections::hash_map::HashMap;

use mul_model::*;
use rpcx::Client;
use rpcx::{Result, SerializeType};

pub fn main() {
    let mut c: Client = Client::new("127.0.0.1:8972");
    c.start().map_err(|err| println!("{}", err)).unwrap();
    c.opt.serialize_type = SerializeType::JSON;

    let mut a = 1;
    loop {
        let service_path = String::from("Arith");
        let service_method = String::from("Mul");
        let metadata = HashMap::new();
        let args = ArithAddArgs { a: a, b: 10 };
        a += 1;

        let reply: Option<Result<ArithAddReply>> =
            c.call(service_path, service_method, false, metadata, &args);
        match reply {
            Some(Ok(r)) => println!("received: {:?}", r),
            Some(Err(err)) => println!("received err:{}", err),
            None => {}
        }
    }
}

Actually you can use this client to access rpcx services implemented by other program languages such as service in go.

As you see, only after three steps you have expored Rust functions (add and mul) as rpc services.

You can find more examples at rpcx-rs/examples

License

rpcx-rs is distributed under the terms of both the MIT license.

See LICENSE-APACHE and LICENSE-MIT, and COPYRIGHT for details.

Comments

  • Update README.md
    Update README.md

    Apr 16, 2020

                                                                                                                                                                                                           
    Reply
  • Updated the README example to be more idiomatic
    Updated the README example to be more idiomatic

    Aug 13, 2019

                                                                                                                                                                                                           
    Reply
  • 关于register_func! 注册一个对象的方法有什么办法吗?
    关于register_func! 注册一个对象的方法有什么办法吗?

    Jan 5, 2020

    我想注册

        register_func!(
            rpc_server,
            RPC_PS_Path,
            RPC_PS_Write,
            write,
            "".to_owned(),
            WriteRequest,
            WriteResponse
        );
    

    如果方法绑定在对象上 如

    struct AAA{
    }
    
    impl AAA{
        pub fn write(req) -> rep {}
    }
    
    
     register_func!(
            rpc_server,
            RPC_PS_Path,
            RPC_PS_Write,
            AAA.write,
            "".to_owned(),
            WriteRequest,
            WriteResponse
        );
    
    

    不行的。

    然后我用闭包

    let write = |x: WriteRequest| -> WriteResponse {
            let rep: WriteResponse = Default::default();
            rep
        };
    
     register_func!(
            rpc_server,
            RPC_PS_Path,
            RPC_PS_Write,
            write,
            "".to_owned(),
            WriteRequest,
            WriteResponse
        );
    
    

    还是不工作,这个问题该如何处理呀?谢谢

    Reply
  • 这个client 必须是 mut 的 是必须的吗?
    这个client 必须是 mut 的 是必须的吗?

    Jan 8, 2020

    image 这样很不方便复用,不过我rust 不太熟悉。我理解的对吗

    Reply