Background
Indeed in the 3.x release one of the explicit goals was to make remote functions easier and more ergonomic to use, you can read more about the motivation for that here.
To help achieving this goal we removed Protobuf from the SDK surface (we still use it internally) and we came up with the Message and types abstractions.
Since the embedded SDK is considered to be more of a power-user SDK, there you would still use Protobuf for communicating with remote functions. Although this is something we would like to simplify as well but there are some technical issues.
TypedValue
This is a Protobuf message that is used internally, whenever a remote function invokes another remote function.
message TypedValue {
string typename = 1;
// has_value is set to differentiate a zero length value bytes explicitly set,
// or a non existing value.
bool has_value = 2;
bytes value = 3;
}
The typename field is a string of the form / that is defined by the user. for example: "com.kkrugler.types/MyEvent". StateFun will pass that string as-us, and treats that as an opaque type tag, to be interpreted by the user on the remote SDK side.
has_value in this context, needs to be always set to true. (it is considered an error to send a message without a payload.
values - is a serialised, opaque value of the type typename.
Embedded Functions
An embedded function that needs to invoke a remote function, needs invoke it with a TypedValue instance.
The remote SDKs know how to convert a TypedValue into a Message class.
Drop in replacement for Any
Here is a useful method for wrapping a Protobuf message with a TypedValue:
public static <M extends Message> TypedValue pack(M message) {
return TypedValue.newBuilder()
.setTypename("type.googleapis.com/" + message.getDescriptorForType().getFullName())
.setHasValue(true)
.setValue(message.toByteString())
.build();
}
Then, simply use it like that:
MyProtobufEvent myProtobufEvent = MyProtobufEvent.newBuilder() ... build();
context.send(.., pack(myProtobufEvent));
On the remote SDK side (assuming Python, since you've mentioned that):
from statefun import make_protobuf_type
MyProtobufEventType = make_protobuf_type(MyProtobufEvent)
...
myProtobufEvent = message.as_type(MyProtobufEventType)