# logimesh
`logimesh` is a Rust microcomponent 2.0 framework inspired by the [_Towards Modern Development of Cloud Applications_](https://dl.acm.org/doi/pdf/10.1145/3593856.3595909) paper.
_(This is one of my amateur idea and is only developed in leisure-time.)_
[](https://crates.io/crates/logimesh)
[](https://docs.rs/logimesh)
[](https://github.com/andeya/logimesh?tab=MIT-1-ov-file)

## Some features of logimesh:
- The client supports both local calls and remote calls simultaneously, meaning that users can dynamically switch the calling method according to the context.
## Usage
Add to your `Cargo.toml` dependencies:
```toml
logimesh = "0.1"
```
The `logimesh::component` attribute expands to a collection of items that form an component component.
These generated types make it easy and ergonomic to write servers with less boilerplate.
Simply implement the generated component trait, and you're off to the races!
## Example
This example uses [tokio](https://tokio.rs), so add the following dependencies to
your `Cargo.toml`:
```toml
anyhow = "1.0"
futures = "0.3"
logimesh = { version = "0.1" }
tokio = { version = "1.0", features = ["macros"] }
```
In the following example, we use an in-process channel for communication between
client and server. In real code, you will likely communicate over the network.
For a more real-world example, see [logimesh-example](logimesh-example).
First, let's set up the dependencies and component definition.
```rust
# extern crate futures;
use futures::{
prelude::*,
};
use logimesh::{
client, context,
server::{self, incoming::Incoming, Channel},
};
// This is the component definition. It looks a lot like a trait definition.
// It defines one RPC, hello, which takes one arg, name, and returns a String.
#[logimesh::component]
trait World {
/// Returns a greeting for name.
async fn hello(name: String) -> String;
}
```
This component definition generates a trait called `World`. Next we need to
implement it for our Server struct.
```rust
# extern crate futures;
# use futures::{
# prelude::*,
# };
# use logimesh::{
# client, context,
# server::{self, incoming::Incoming},
# };
# // This is the component definition. It looks a lot like a trait definition.
# // It defines one RPC, hello, which takes one arg, name, and returns a String.
# #[logimesh::component]
# trait World {
# /// Returns a greeting for name.
# async fn hello(name: String) -> String;
# }
/// This is the type that implements the generated World trait. It is the business logic
/// and is used to start the server.
#[derive(Clone)]
struct CompHello;
impl World for CompHello {
// Each defined rpc generates an async fn that serves the RPC
async fn hello(self, _: context::Context, name: String) -> String {
format!("Hello, {name}!")
}
}
```
Lastly let's write our `main` that will start the server. While this example uses an
[in-process channel](transport::channel), lrcall also ships a generic [`serde_transport`]
behind the `serde-transport` feature, with additional [TCP](serde_transport::tcp) functionality
available behind the `tcp` feature.
```rust
# extern crate futures;
# use futures::{
# prelude::*,
# };
# use logimesh::{
# client, context,
# server::{self, incoming::Incoming},
# };
# // This is the component definition. It looks a lot like a trait definition.
# // It defines one RPC, hello, which takes one arg, name, and returns a String.
# #[logimesh::component]
# trait World {
# /// Returns a greeting for name.
# async fn hello(name: String) -> String;
# }
# /// This is the type that implements the generated World trait. It is the business logic
# /// and is used to start the server.
# #[derive(Clone)]
# struct CompHello;
#
# impl World for CompHello {
# // Each defined rpc generates an async fn that serves the RPC
# async fn hello(self, _: context::Context, name: String) -> String {
# format!("Hello, {name}!")
# }
# }
async fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
tokio::spawn(fut);
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let (client_transport, server_transport) = logimesh::transport::channel::unbounded();
let server = server::BaseChannel::with_defaults(server_transport);
tokio::spawn(server.execute(CompHello.logimesh_serve()).for_each(spawn));
// WorldClient is generated by the #[logimesh::component] attribute. It has a constructor `new`
// that takes a config and any Transport as input.
let client = WorldClient::new(client::Config::default(), client_transport).spawn();
// The client has an RPC method for each RPC defined in the annotated trait. It takes the same
// args as defined, with the addition of a Context, which is always the first arg. The Context
// specifies a deadline and trace information which can be helpful in debugging requests.
let hello = client.hello(context::current(), "Andeya".to_string()).await?;
println!("{hello}");
Ok(())
}
```