Can we also generate services along with outputting types?
Taking this proto file as an example:
https://github.com/lightningnetwork/lnd/blob/master/lnrpc/invoicesrpc/invoices.proto#L29
The rpc services functions are not getting generated. Only the types are. Is it possible to also add this?
Hello,
I have no plan of implementing the full gRPC protocol by myself, but i guess we could generate interface structures that the user would fill with the implementations.
something naive like
// generated part
const SubscribeSingleInvoiceRequest = struct {
// generated struct
};
const Invoice = struct {
// generated struct
};
pub fn InvoiceServicesImplementations(comptime ServerContext: type) type {
return struct {
SubscribeSingleInvoiceMethod : *const fn(server: *ServerContext, request: SubscribeSingleInvoiceRequest) Invoice
};
}
pub fn InvoicesService(comptime ServerContext: type) type {
return struct {
context: *ServerContext,
implementations: InvoiceServicesImplementations(ServerContext),
const Self = @This();
pub fn SubscribeSingleInvoice(self: *Self, request: SubscribeSingleInvoiceRequest) Invoice {
return self.implementations.SubscribeSingleInvoiceMethod(self.context, request);
}
};
}
// user defined part
const Server = struct {
something: u32
};
fn implementation(server: *Server, _: SubscribeSingleInvoiceRequest) Invoice {
server.something = 1;
std.debug.print("doing stuff", .{});
return Invoice{};
}
test "services" {
var server = Server{
.something = 0,
};
var service = InvoicesService(Server){
.context = &server,
.implementations = .{
.SubscribeSingleInvoiceMethod = implementation
}
};
_ = service.SubscribeSingleInvoice(SubscribeSingleInvoiceRequest{});
try testing.expectEqual(1, server.something);
}
would probably be a good starting block, even for a future gRPC implementation.
Actually, i thought services in proto files were meant to be only gRPC services, but no, you can define your own transport protocol according to the spec itself
So i guess we were missing this part entirely.
I'll work on it soon-ish, thanks for the heads up.
Thank you
@niteshbalusu11 ongoing work in #40 , i'm going for the common interface pattern found in the standard library. services will look like this with implementations possibly like that, see test below.
This is a draft, i plan on bringing a bit more stuff around, but that's the idea.
Would that be ok?
I realized that error handling was completely missing in what i was about to propose.
The thing is, i'm not sure how to handle it correctly. I have two ideas about it:
- making the error type a specialization of the interface, giving full control to the end user but losing the completely generic interface. Can be seen in this example
- Making sensible default error types, with a CustomError escape latch that implementation can use to refer to some error saved in the process. This can be seen here.
First method loses the generic interface, which i don't like. Second method keeps the generic interface but makes it slightly harder for precise error handling for end users.
@niteshbalusu11 any opinion?
@menduz got any idea, considering you're my only reviewer around?
I honestly don't know. Maybe it's good to check how the other parsing libraries do it?
I think i'll go with solution 2, i prefer to keep the generic interfaces.