Custom Tower transport layer for generic service?

Hi all!

So, I've been working on an implementation of the actor model, with remote actors. And it works, kind of. The problem is that the code is quite honestly a hot mess lmao.

Reading about Tower, I thought maybe I could refactor my stuff around it, with a core Service for the actors themselves, and a network Layer to read (and try to decrypt) and write (after encrypting) messages. But I couldn't find any examples of a custom transport with Tower! Only HTTP services.

Is what I want to do even practical in Tower? If so, I'm probably going the wrong way about this. Why?

use std::{
    future::Future,
    net::TcpStream,
    pin::Pin,
    task::{Context, Poll},
};

use tower::Service;

pub struct Message<T: Send>(T);

// This is the only trait the library should expose to the users
pub trait Actor<I, O, E> {
    // I don't like that this returns an explicit, pinned, boxed future
    // but otherwise I would have lifetime issues in call, which requires
    // &self to be 'static
    fn handle(&mut self, arg: I) -> Pin<Box<dyn Future<Output = Result<O, E>>>>;
}

// everything from this point onwards is internal machinery, not to be exposed to the user

impl<I, O, E> Service<I> for dyn Actor<I, O, E>
where
    I: 'static,
    O: 'static,
    E: 'static,
{
    type Response = O;
    type Error = E;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: I) -> Self::Future {
        let future = self.handle(req);

        Box::pin(future)
    }
}

struct ActorTransport<T>(T);

impl<T> Service<TcpStream> for ActorTransport<T>
where
    T: Service<I>, // <- can't find type parameter, and even if I specified it,
                   // it wouldn't be constrained anywhere else
{
    type Response = (); // what should the response even be?
    type Error = (); // same with this error -- maybe if the deserialization fails?
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: TcpStream) -> Self::Future {
        // 1. read a message from the stream
        // 2. deserialize it
        // 3. call self.0.call(...)
        // 4. serialize the result and send it back
        // 5? what should the response be?

        todo!()
    }
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.