Skip to content

RustBasicService

Anson edited this page Jan 8, 2026 · 1 revision

Using Services in Rust - Example 15

This example is a reimplementation of example 4 in Rust. There's really not much to say here, as in the previous example the code is very similar to the code in the C++ version.

The Service Provider (BasicServiceProvider)

For the provider, we first set up the request listener:

struct MultiplicationServiceProvider {}

impl GravityServiceProvider for MultiplicationServiceProvider {
    fn request(&mut self, _service_id: &str, data_product: &GravityDataProduct) -> GravityDataProduct {
        
		//Just to be safe. In theory this can never happen unless this class is registered with more than one serviceID types.
        if data_product.data_product_id() != "Multiplication" {
            SpdLog::error("Request is not for multiplication!");
            return GravityDataProduct::with_id("BadRequest");
        }

        // Get the params for this result
        let mut params = MultiplicationOperandsPB::new();
        data_product.populate_message(&mut params);

        SpdLog::warn(format!(
            "Request Received: {} x {}",
            params.multiplicand_a(),
            params.multiplicand_b()));

        // Do the calculation
        let result = params.multiplicand_a() * params.multiplicand_b();

        // Return the results to the requestor
        let mut result_pb = MultiplicationResultPB::new();
        result_pb.set_result(result);

        let result_gdp = GravityDataProduct::with_id("MultiplicationResult");
        result_gdp.set_data(&result_pb);

        result_gdp
    }   
}

Once that's done, we can register it:

let msp = MultiplicationServiceProvider {};
gn.register_service(
		//This identifies the Service to the service directory so that others can
		// make a request to it.
		"Multiplication",
		//Assign a transport type to the socket (almost always tcp, unless you are only
		//using the gravity data product between two processes on the same computer).
		GravityTransportType.TCP,
		//Give an instance of the multiplication service trait to be called when a request is made for multiplication.
		// Note that this is not a token, but you are directly giving the GravityNode ownership of the GravityServiceProvider
		msp);

The Requester (BasicServiceRequestor)

And for the requester, we setup the response listener:

struct MultiplicationRequestor {}

//After multiplication is requested, this trait object may be called with the result.
impl GravityRequestor for MultiplicationRequestor {
    fn request_filled(&mut self, _service_id: &str, request_id: &str, response: &GravityDataProduct) {
        // Parse the message into a protobuf
        let mut result = MultiplicationResultPB::new();
        response.populate_message(&mut result);

        // Write the answer
        SpdLog::warn(format!(
            "Asynchronous response received: {} = {}", request_id, result.result()
        ));
        
        let mut data = GOT_ASYNC.lock().expect("Something already has this");
        *data = true;
    }

    fn request_timeout(&mut self, _: &str, _: &str) {
        
    }
}

And then we make the asynchronous request that uses the listener:

/////////////////////////////
// Set up the first multiplication request
let requestor = gn.tokenize_requestor(MultiplicationRequestor {});
let mult_request1 = GravityDataProduct::with_id("Multiplication");
let mut params1 = MultiplicationOperandsPB::new();
params1.set_multiplicand_a(8);
params1.set_multiplicand_b(2);
mult_request1.set_data(&params1);


// Make an asynchronous request 
while gn.request_async_with_request_id(
    "Multiplication",  // Service name
    &mult_request1,    // Request
    &requestor,        // token representing the object with the callback
    "8 x 2"            // string identifying which request this is
) != GravityReturnCode::SUCCESS {
    SpdLog::warn("request to Multiplication servicec failed, retrying...");
    std::thread::sleep(time::Duration::from_millis(1000));
}

And lastly, we make the synchronous request against the same service:

/////////////////////////////////////////
// Set up the second multiplication request
let mult_request2 = GravityDataProduct::with_id("Multiplication");
let mut params2 = MultiplicationOperandsPB::new();
params2.set_multiplicand_a(5);
params2.set_multiplicand_b(7);
mult_request2.set_data(&params2);

// Make a synchronous request for multiplication
// Returns Option<GravityDataProduct>
let mult_sync = gn.request_sync_with_timeout(
    "Multiplication",   // Service name
    &mult_request2,     // Request
    1000);    			// Timeout in milliseconds

match mult_sync {
    None => SpdLog::error("Request returned None"),
    Some( gdp ) => {
        let mut result = MultiplicationResultPB::new();
        gdp.populate_message(&mut result);
        SpdLog::warn(format!(
            "Synchronous response received: 5 x 7 = {}", result.result()
        ));
    }
}

Clone this wiki locally