36 releases (stable)

✓ Uses Rust 2018 edition

8.1.0 May 15, 2019
7.0.1 Mar 11, 2019
7.0.0 Jan 9, 2019
5.3.0 Dec 13, 2018
0.4.0 Mar 29, 2018

#185 in Network programming

Download history 26/week @ 2019-01-25 15/week @ 2019-02-01 3/week @ 2019-02-08 26/week @ 2019-02-15 10/week @ 2019-02-22 102/week @ 2019-03-01 46/week @ 2019-03-08 55/week @ 2019-03-15 175/week @ 2019-03-22 9/week @ 2019-03-29 37/week @ 2019-04-05 9/week @ 2019-04-12 36/week @ 2019-04-19 3/week @ 2019-04-26 37/week @ 2019-05-03

183 downloads per month
Used in 2 crates

MIT/Apache

90KB
2K SLoC

varlink

The varlink crate provides support to implement client and server using the varlink protocol.

See http://varlink.org for more information about varlink.

Build Status Crate

More Info


lib.rs:

Server and client support for the varlink protocol

Server

To create a varlink server in rust, place your varlink interface definition file in src/. E.g. src/org.example.ping.varlink:

# Example service
interface org.example.ping

# Returns the same string
method Ping(ping: string) -> (pong: string)

Then create a build.rs file in your project directory:

extern crate varlink_generator;

fn main() {
    varlink_generator::cargo_build_tosource("src/org.example.ping.varlink",
                                             /* rustfmt */ true);
}

For more code generation functions see the generator functions.

Add to your Cargo.toml:

[package]
build = "build.rs"
[build-dependencies]
varlink_generator = "<version>"

In your main.rs you can then use:

mod org_example_ping;

and then implement the interface:

# #![allow(non_camel_case_types)]
# #![allow(non_snake_case)]
# use std::io;
# use varlink::{CallTrait, Result};
# struct Ping_Reply {pong: String}
# impl varlink::VarlinkReply for Ping_Reply {}
# struct _PingArgs {ping: String}
# pub trait VarlinkCallError: varlink::CallTrait {}
# impl<'a> VarlinkCallError for varlink::Call<'a> {}
# pub trait Call_Ping: VarlinkCallError {
#     fn reply(&mut self, pong: String) -> Result<()> { Ok(()) }
# }
# impl<'a> Call_Ping for varlink::Call<'a> {}
# pub trait VarlinkInterface {
#     fn ping(&self, call: &mut Call_Ping, ping: String) -> Result<()>;
#     fn call_upgraded(&self, _call: &mut varlink::Call, bufreader: &mut io::BufRead) ->
# Result<Vec<u8>> {Ok(Vec::new())}
# }
# pub struct _InterfaceProxy {inner: Box<VarlinkInterface + Send + Sync>}
# pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {
#     _InterfaceProxy { inner }
# }
# impl varlink::Interface for _InterfaceProxy {
#     fn get_description(&self) -> &'static str { "interface org.example.ping\n\
#                                                  method Ping(ping: string) -> (pong: string)" }
#     fn get_name(&self) -> &'static str { "org.example.ping" }
#     fn call_upgraded(&self, call: &mut varlink::Call, _bufreader: &mut io::BufRead) ->
# Result<Vec<u8>> { Ok(Vec::new()) }
#     fn call(&self, call: &mut varlink::Call) -> Result<()> { Ok(()) }
# }
# fn main() {}
struct MyOrgExamplePing;

impl VarlinkInterface for MyOrgExamplePing {
    fn ping(&self, call: &mut Call_Ping, ping: String) -> Result<()> {
        return call.reply(ping);
    }
}

to implement the interface methods.

If your varlink method is called TestMethod, the rust method to be implemented is called test_method. The first parameter is of type Call_TestMethod, which has the method reply().

# #![allow(non_camel_case_types)]
# #![allow(non_snake_case)]
# use std::io;
# use varlink::{CallTrait, Result};
# pub trait VarlinkCallError: varlink::CallTrait {}
# impl<'a> VarlinkCallError for varlink::Call<'a> {}
# pub trait Call_TestMethod: VarlinkCallError {
#     fn reply(&mut self) -> Result<()> {
#         self.reply_struct(varlink::Reply::parameters(None))
#     }
# }
# impl<'a> Call_TestMethod for varlink::Call<'a> {}
# struct TestService;
# impl TestService {
fn test_method(&self, call: &mut Call_TestMethod, /* more arguments */) -> Result<()> {
    /* ... */
return call.reply( /* more arguments */ );
}
# }
# fn main() {}

A typical server creates a VarlinkService and starts a server via varlink::listen

# #![allow(non_camel_case_types)]
# #![allow(non_snake_case)]
# use std::io;
# mod org_example_ping {
# use std::io;
# use varlink::{self, Result};
# struct Ping_Reply {pong: String}
# impl varlink::VarlinkReply for Ping_Reply {}
# struct _PingArgs {ping: String}
# pub trait VarlinkCallError: varlink::CallTrait {}
# impl<'a> VarlinkCallError for varlink::Call<'a> {}
# pub trait Call_Ping: VarlinkCallError {
#     fn reply(&mut self, pong: String) -> Result<()> { Ok(()) }
# }
# impl<'a> Call_Ping for varlink::Call<'a> {}
# pub trait VarlinkInterface {
#     fn ping(&self, call: &mut Call_Ping, ping: String) -> Result<()>;
#     fn call_upgraded(&self, _call: &mut varlink::Call, bufreader: &mut io::BufRead) ->
# Result<Vec<u8>> {Ok(Vec::new())}
# }
# pub struct _InterfaceProxy {inner: Box<VarlinkInterface + Send + Sync>}
# pub fn new(inner: Box<VarlinkInterface + Send + Sync>) -> _InterfaceProxy {
#     _InterfaceProxy { inner }
# }
# impl varlink::Interface for _InterfaceProxy {
#     fn get_description(&self) -> &'static str { "interface org.example.ping\n\
#                                                  method Ping(ping: string) -> (pong: string)" }
#     fn get_name(&self) -> &'static str { "org.example.ping" }
#     fn call_upgraded(&self, call: &mut varlink::Call, _bufreader: &mut io::BufRead) ->
# Result<Vec<u8>> { Ok(Vec::new()) }
#     fn call(&self, call: &mut varlink::Call) -> Result<()> { Ok(()) }
# }}
# use crate::org_example_ping::*;
#
# struct MyOrgExamplePing;
#
# impl org_example_ping::VarlinkInterface for MyOrgExamplePing {
#     fn ping(&self, call: &mut Call_Ping, ping: String) -> varlink::Result<()> {
#         return call.reply(ping);
#     }
# }
# fn main_func() {
let args: Vec<_> = std::env::args().collect();
let myorgexampleping = MyOrgExamplePing;
let myorgexampleping_interface = org_example_ping::new(Box::new(myorgexampleping));

let service = varlink::VarlinkService::new(
    "org.varlink",
    "test service",
    "0.1",
    "http://varlink.org",
    vec![
        Box::new(myorgexampleping_interface),
        // more interfaces ...
    ],
);

varlink::listen(service, &args[1], 1, 10, 0);
# }
# fn main() {}

where args[1] would follow the varlink address specification.

Currently supported address URIs are:

  • TCP tcp:127.0.0.1:12345 hostname/IP address and port
  • UNIX socket unix:/run/org.example.ftl optional access ;mode=0666 parameter
  • UNIX abstract namespace socket unix:@org.example.ftl (on Linux only)

Client

Setup your project, just like in the server case with a varlink file and a build.rs file.

In your main.rs you can then use:

mod org_example_ping;
use org_example_ping;
let connection = Connection::with_address("unix:/tmp/org.example.ping").unwrap();
let mut ping_service = org_example_ping::VarlinkClient::new(connection);
let reply = ping_service.ping(String::from("Test")).call()?;
assert_eq!(String::from("Test"), reply.pong);

A connection can be established via the connection builder functions. The org_example_ping::VarlinkClient implements org_example_ping::VarlinkClientInterface, which has all the varlink methods (names converted from camel case to lowercase snake case). The PingString() method would be named ping_string().

To iterate over a more call

for reply in my_more_service.test_more(/* params */).more()? { /*...*/ }

The reply struct is placed in a structure named after the method with _Reply appended. So, the reply to the Ping() method in our example is in a struct called Ping_Reply.

Dependencies

~2.5MB
~46K SLoC