subliminal_protos_rust/
lib.rs

1pub mod errors;
2
3use broker::broker_client::BrokerClient;
4use db::db_handler_client::DbHandlerClient;
5use log::info;
6use service_registry::{service_registry_client::ServiceRegistryClient, GetServiceRequest};
7use tonic::transport::Channel;
8use ulid::{DecodeError, Ulid};
9
10#[path = "codegen/db.rs"]
11pub mod db;
12
13#[path = "codegen/service_registry.rs"]
14pub mod service_registry;
15
16#[path = "codegen/broker.rs"]
17pub mod broker;
18
19/// Get a datastore client using the provided service registry channel.
20/// Will return a tonic::NotFound error if the datastore is not registered in the service registry.
21/// Will return a tonic::Internal error if the service registry returns an unexpected error.
22/// Will return a tonic::Unavailable error if the datastore cannot be reached.
23pub async fn get_datastore_client(
24    service_registry_channel: Channel,
25) -> Result<DbHandlerClient<Channel>, tonic::Status> {
26    // Build the service registry client from the provided channel
27    let mut service_registry_client: ServiceRegistryClient<Channel> =
28        ServiceRegistryClient::new(service_registry_channel);
29
30    // Get the database handler address from the provided service registry
31    let datastore_url = match service_registry_client
32        .get_service(GetServiceRequest {
33            service_name: String::from("db"),
34        })
35        .await
36    {
37        Ok(response) => {
38            let resp = response.into_inner();
39            format!("http://{}:{}", resp.service_address, resp.service_port)
40        }
41        // We don't want to just pass any error along (because clients don't need nor want to handle every case),
42        // Instead, we filter the error and return a more concise error type/message so it's easier for the client to handle
43        Err(e) => match e.code() {
44            tonic::Code::NotFound => {
45                return Err(tonic::Status::new(
46                    tonic::Code::NotFound,
47                    "Message broker not found in service registry",
48                ))
49            }
50            _ => return Err(tonic::Status::new(tonic::Code::Internal, e.to_string())),
51        },
52    };
53
54    // Using the address, connect to the database handler and return the client
55    DbHandlerClient::connect(datastore_url)
56        .await
57        .map_err(|e| tonic::Status::new(tonic::Code::Unavailable, e.to_string()))
58}
59
60/// Get a message broker client using the provided service registry channel.
61/// Will return a tonic::NotFound error if the message broker is not registered in the service registry.
62/// Will return a tonic::Internal error if the service registry returns an unexpected error.
63/// Will return a tonic::Unavailable error if the message broker cannot be reached.
64pub async fn get_message_broker_client(
65    message_broker_channel: Channel,
66) -> Result<BrokerClient<Channel>, tonic::Status> {
67    // Build the service registry client from the provided channel
68    let mut service_registry_client: ServiceRegistryClient<Channel> =
69        ServiceRegistryClient::new(message_broker_channel);
70
71    // Get the message broker address from the provided service registry
72    let message_broker_url = match service_registry_client
73        .get_service(GetServiceRequest {
74            service_name: String::from("message_broker"),
75        })
76        .await
77    {
78        Ok(response) => {
79            let resp = response.into_inner();
80            format!("http://{}:{}", resp.service_address, resp.service_port)
81        }
82        // We don't want to just pass any error along (because clients don't need nor want to handle every case),
83        // Instead, we filter the error and return a more concise error type/message so it's easier for the client to handle
84        Err(e) => match e.code() {
85            tonic::Code::NotFound => {
86                return Err(tonic::Status::new(
87                    tonic::Code::NotFound,
88                    "Message broker not found in service registry",
89                ))
90            }
91            _ => return Err(tonic::Status::new(tonic::Code::Internal, e.to_string())),
92        },
93    };
94
95    // Using the address, connect to the message broker and return the client
96    BrokerClient::connect(message_broker_url)
97        .await
98        .map_err(|e| tonic::Status::new(tonic::Code::Unavailable, e.to_string()))
99}
100
101/// Quick helper function to verify that a ULID is valid.
102/// We need this because the ULID type does not implement the JsonSchema trait that
103/// would allow us to validate the ULID in the request directly. We don't need
104/// to return the ULID itself since Redis just uses the string representation.
105pub fn parse_ulid(id: &str) -> Result<Ulid, DecodeError> {
106    let res = id.parse::<Ulid>();
107    match res {
108        Ok(ulid) => Ok(ulid),
109        Err(e) => {
110            info!("Error parsing ULID: {}", e);
111            Err(e)
112        }
113    }
114}