From b42adfbe861bab34896e9b54d6c901f3a09a992f Mon Sep 17 00:00:00 2001 From: Noctunus Date: Tue, 1 Oct 2024 15:23:15 +0200 Subject: [PATCH] Next iteration of automatic code generation --- .../messaging/clients/ping_client_example.go | 28 ---- .../clients/ping_client_method_example.go | 24 ---- scripts/generateGRPCServiceHandlers.sh | 127 +++++++++++++++--- templates/client.go.tpl | 10 +- templates/client_method.go.tpl | 6 +- 5 files changed, 118 insertions(+), 77 deletions(-) delete mode 100644 internal/messaging/clients/ping_client_example.go delete mode 100644 internal/messaging/clients/ping_client_method_example.go diff --git a/internal/messaging/clients/ping_client_example.go b/internal/messaging/clients/ping_client_example.go deleted file mode 100644 index 21b8362..0000000 --- a/internal/messaging/clients/ping_client_example.go +++ /dev/null @@ -1,28 +0,0 @@ -// Code generated by '{{GENERATOR}}'. DO NOT EDIT. -// template: {{TEMPLATE}} - -package clients - -import ( - "buf.build/gen/go/chain4travel/camino-messenger-protocol/grpc/go/cmp/services/ping/v1/pingv1grpc" - "github.com/chain4travel/camino-messenger-bot/internal/messaging/types" - - "google.golang.org/grpc" -) - -const ( - PingServiceV1 = "cmp.services.ping.v1.PingService" - PingServiceV1Request types.MessageType = types.MessageType(PingServiceV1 + ".Request") - PingServiceV1Response types.MessageType = types.MessageType(PingServiceV1 + ".Response") -) - -var _ Client = (*PingClient)(nil) - -func NewPingServiceV1(grpcCon *grpc.ClientConn) *PingClient { - client := pingv1grpc.NewPingServiceClient(grpcCon) - return &PingClient{client: &client} -} - -type PingClient struct { - client *pingv1grpc.PingServiceClient -} diff --git a/internal/messaging/clients/ping_client_method_example.go b/internal/messaging/clients/ping_client_method_example.go deleted file mode 100644 index 4e5691e..0000000 --- a/internal/messaging/clients/ping_client_method_example.go +++ /dev/null @@ -1,24 +0,0 @@ -// Code generated by '{{GENERATOR}}'. DO NOT EDIT. -// template: {{TEMPLATE}} - -package clients - -import ( - "context" - "fmt" - - pingv1 "buf.build/gen/go/chain4travel/camino-messenger-protocol/protocolbuffers/go/cmp/services/ping/v1" - "github.com/chain4travel/camino-messenger-bot/internal/messaging/types" - - "google.golang.org/grpc" - "google.golang.org/protobuf/reflect/protoreflect" -) - -func (s PingClient) Call(ctx context.Context, requestIntf protoreflect.ProtoMessage, opts ...grpc.CallOption) (protoreflect.ProtoMessage, types.MessageType, error) { - request, ok := requestIntf.(*pingv1.PingRequest) - if !ok { - return nil, PingServiceV1Response, fmt.Errorf("invalid request type") - } - response, err := (*s.client).Ping(ctx, request, opts...) - return response, PingServiceV1Response, err -} diff --git a/scripts/generateGRPCServiceHandlers.sh b/scripts/generateGRPCServiceHandlers.sh index 481ef5b..17a2de0 100755 --- a/scripts/generateGRPCServiceHandlers.sh +++ b/scripts/generateGRPCServiceHandlers.sh @@ -1,21 +1,33 @@ #!/bin/bash -function generate() { +TEMPLATES_DIR="templates" +CLIENT_TEMPLATE="${TEMPLATES_DIR}/client.go.tpl" +CLIENT_METHOD_TEMPLATE="${TEMPLATES_DIR}/client_method.go.tpl" +SERVER_TEMPLATE="${TEMPLATES_DIR}/server.go.tpl" +SERVER_METHOD_TEMPLATE="${TEMPLATES_DIR}/server_method.go.tpl" + +GEN_OUTPATH_CLIENT="internal/messaging/clients" +GEN_OUTPATH_SERVER="internal/rpc/server" + +function generate_with_templates() { FQPN=$1 SERVICE=$2 - PACKAGE=$3 - TYPE=$4 + GRPC_PACKAGE=$3 + TYPE_PACKAGE=$4 local -n _METHODS=$5 local -n _INPUTS=$6 local -n _OUTPUTS=$7 GRPC_INCLUDE=$8 PROTO_INCLUDE=$9 + VERSION=${10} + GENERATOR=${11} echo "Generating with parameters:" - echo "FQPN : $FQPN" - echo "SERVICE : $SERVICE" - echo "PACKAGE : $PACKAGE" - echo "TYPE : $TYPE" + echo "FQPN : $FQPN" + echo "SERVICE : $SERVICE" + echo "GRPC_PACKAGE : $GRPC_PACKAGE" + echo "TYPE_PACKAGE : $TYPE_PACKAGE" + echo "VERSION : $VERSION" for num in `seq 0 $(( ${#_METHODS[@]} - 1 ))` ; do echo "METHOD[$num]: ${_METHODS[$num]} ${_INPUTS[$num]} ${_OUTPUTS[$num]}" # does each method has an independent file? If not how should the template work? @@ -27,15 +39,89 @@ function generate() { # From here on it's very easy in case it's just search replace # Simply copy the template to the target directory # And do some sed -i -e "s#{{.FQDN}}#$FQDN#g" -e "s#{{.SERVICE}}#$SERVICE#g" [...] $file - PARAM_REPLACE="" - PARAM_REPLACE+=" -e 's#{{.FQPN}}#$FQPN#g'" - PARAM_REPLACE+=" -e 's#{{.SERVICE}}#$SERVICE#g'" - PARAM_REPLACE+=" -e 's#{{.PACKAGE}}#$PACKAGE#g'" - PARAM_REPLACE+=" -e 's#{{.TYPE}}#$TYPE#g'" - PARAM_REPLACE+=" -e 's#{{.GRPC_INCLUDE}}#$GRPC_INCLUDE#g'" - PARAM_REPLACE+=" -e 's#{{.PROTO_INCLUDE}}#$PROTO_INCLUDE#g'" + GENERAL_PARAM_REPLACE="" + GENERAL_PARAM_REPLACE+=" -e s#{{FQPN}}#$FQPN#g" + GENERAL_PARAM_REPLACE+=" -e s#{{SERVICE}}#$SERVICE#g" + GENERAL_PARAM_REPLACE+=" -e s#{{GRPC_PACKAGE}}#$GRPC_PACKAGE#g" + GENERAL_PARAM_REPLACE+=" -e s#{{TYPE_PACKAGE}}#$TYPE_PACKAGE#g" + GENERAL_PARAM_REPLACE+=" -e s#{{GRPC_INC}}#$GRPC_INCLUDE#g" + GENERAL_PARAM_REPLACE+=" -e s#{{PROTO_INC}}#$PROTO_INCLUDE#g" + GENERAL_PARAM_REPLACE+=" -e s#{{VERSION}}#$VERSION#g" + GENERAL_PARAM_REPLACE+=" -e s#{{GENERATOR}}#$GENERATOR#g" + + # Generate client + CLIENT_GEN_FILE="${GEN_OUTPATH_CLIENT}/${TYPE_PACKAGE}_client.go" + echo "Generating client: $CLIENT_GEN_FILE" + cp $CLIENT_TEMPLATE $CLIENT_GEN_FILE + sed -i $GENERAL_PARAM_REPLACE $CLIENT_GEN_FILE + sed -i -e "s#{{TEMPLATE}}#$CLIENT_TEMPLATE#g" $CLIENT_GEN_FILE + + # Generate client methods + for num in `seq 0 $(( ${#_METHODS[@]} - 1 ))` ; do + METHOD=${_METHODS[$num]} + INPUT=${_INPUTS[$num]} + OUTPUT=${_OUTPUTS[$num]} + METHOD_PARAM_REPLACE="" + METHOD_PARAM_REPLACE+=" -e s#{{METHOD}}#$METHOD#g" + METHOD_PARAM_REPLACE+=" -e s#{{REQUEST}}#$INPUT#g" + METHOD_PARAM_REPLACE+=" -e s#{{RESPONSE}}#$OUTPUT#g" + METHOD_GEN_FILE="${GEN_OUTPATH_CLIENT}/${TYPE_PACKAGE}_${METHOD}_method.go" + echo "Generating client method: $METHOD_GEN_FILE" + cp $CLIENT_METHOD_TEMPLATE $METHOD_GEN_FILE + sed -i $GENERAL_PARAM_REPLACE $METHOD_GEN_FILE + sed -i $METHOD_PARAM_REPLACE $METHOD_GEN_FILE + sed -i -e "s#{{TEMPLATE}}#$CLIENT_METHOD_TEMPLATE#g" $METHOD_GEN_FILE + done + + # Generate server + SERVER_GEN_FILE="${GEN_OUTPATH_SERVER}/${TYPE_PACKAGE}_server.go" + echo "Generating server: $SERVER_GEN_FILE" + cp $SERVER_TEMPLATE $SERVER_GEN_FILE + sed -i $GENERAL_PARAM_REPLACE $SERVER_GEN_FILE + sed -i -e "s#{{TEMPLATE}}#$SERVER_TEMPLATE#g" $SERVER_GEN_FILE + + # Generate server methods + for num in `seq 0 $(( ${#_METHODS[@]} - 1 ))` ; do + METHOD=${_METHODS[$num]} + INPUT=${_INPUTS[$num]} + OUTPUT=${_OUTPUTS[$num]} + METHOD_PARAM_REPLACE="" + METHOD_PARAM_REPLACE+=" -e s#{{METHOD}}#$METHOD#g" + METHOD_PARAM_REPLACE+=" -e s#{{REQUEST}}#$INPUT#g" + METHOD_PARAM_REPLACE+=" -e s#{{RESPONSE}}#$OUTPUT#g" + METHOD_GEN_FILE="${GEN_OUTPATH_SERVER}/${TYPE_PACKAGE}_${METHOD}_method.go" + echo "Generating server method: $METHOD_GEN_FILE" + cp $SERVER_METHOD_TEMPLATE $METHOD_GEN_FILE + sed -i $GENERAL_PARAM_REPLACE $METHOD_GEN_FILE + sed -i $METHOD_PARAM_REPLACE $METHOD_GEN_FILE + sed -i -e "s#{{TEMPLATE}}#$SERVER_METHOD_TEMPLATE#g" $METHOD_GEN_FILE + done + + ## TODO: When done generating also run: + ## gofumpt -l -w +} + +REGISTER_SERVICES_FILE="internal/rpc/server/register_services.go" + +function generate_register_services() { + OUTFILE=$1 + local -n _SERVICES=$2 + + echo "📝 Registering services in $REGISTER_SERVICES_FILE" + + echo "// Code generated by '{{GENERATOR}}'. DO NOT EDIT." > $OUTFILE + echo >> $OUTFILE + echo "package server" >> $OUTFILE + echo >> $OUTFILE + echo "func (s *server) registerServices() {" >> $OUTFILE + for service in ${_SERVICES[@]} ; do + echo " register${service}Server(s.grpcServer, s)" >> $OUTFILE + done + echo "}" >> $OUTFILE } +SCRIPT=$0 + BUF_SDK_BASE="buf.build/gen/go/chain4travel/camino-messenger-protocol" BUF_SDK_URL_GO="${BUF_SDK_BASE}/grpc/go" echo "⌛ Downloading SDK from $BUF_SDK_URL_GO" @@ -73,6 +159,7 @@ SDK_PATH="${GO_PATH}/pkg/mod/buf.build/gen/go/chain4travel/camino-messenger-prot echo "SDK_PATH: $SDK_PATH" FILTER=$1 +declare -a SERVICES_TO_REGISTER=() while read file ; do if [ ! -z "$FILTER" ] ; then @@ -122,11 +209,17 @@ while read file ; do declare -a INCLUDES=() # First the protocolbuffers SUFFIX=$(echo ${FQPN%.*} | tr "." "/") - GRPC_INCLUDE="${BUF_SDK_BASE}/protocolbuffers/go/${SUFFIX}" + PROTO_INCLUDE="${BUF_SDK_BASE}/protocolbuffers/go/${SUFFIX}" # Now the grpc which is quite similar by just adding the package name at the end - PROTO_INCLUDE="${BUF_SDK_BASE}/grpc/go/${SUFFIX}/${PACKAGE}" + GRPC_INCLUDE="${BUF_SDK_BASE}/grpc/go/${SUFFIX}/${PACKAGE}" + + VERSION=$(echo "$FQPN" | grep -oP "\.v[0-9]+\." | cut -d"." -f2 ) - generate "$FQPN" "$SERVICE" "$PACKAGE" "$TYPE" METHODS INPUTS OUTPUTS $GRPC_INCLUDE $PROTO_INCLUDE + generate_with_templates "$FQPN" "$SERVICE" "$PACKAGE" "$TYPE" METHODS INPUTS OUTPUTS $GRPC_INCLUDE $PROTO_INCLUDE ${VERSION:1} $SCRIPT + SERVICES_TO_REGISTER+=("${SERVICE}V${VERSION}") echo done < <(find "$SDK_PATH/cmp/services/" -name "*_grpc.pb.go") + +generate_register_services "$REGISTER_SERVICES_FILE" SERVICES_TO_REGISTER + diff --git a/templates/client.go.tpl b/templates/client.go.tpl index 469dff7..1059303 100644 --- a/templates/client.go.tpl +++ b/templates/client.go.tpl @@ -11,18 +11,18 @@ import ( ) const ( - {{SERVICE}}V{{VERSION}} = {{FQPN}} + {{SERVICE}}V{{VERSION}} = "{{FQPN}}" {{SERVICE}}V{{VERSION}}Request types.MessageType = types.MessageType({{SERVICE}}V{{VERSION}} + ".Request") {{SERVICE}}V{{VERSION}}Response types.MessageType = types.MessageType({{SERVICE}}V{{VERSION}} + ".Response") ) -var _ Client = (*{{SERVICE}}Client)(nil) +var _ Client = (*{{SERVICE}}V{{VERSION}}Client)(nil) -func New{{SERVICE}}V{{VERSION}}(grpcCon *grpc.ClientConn) *{{SERVICE}}Client { +func New{{SERVICE}}V{{VERSION}}(grpcCon *grpc.ClientConn) *{{SERVICE}}V{{VERSION}}Client { client := {{GRPC_PACKAGE}}.New{{SERVICE}}Client(grpcCon) - return &{{SERVICE}}Client{client: &client} + return &{{SERVICE}}V{{VERSION}}Client{client: &client} } -type {{SERVICE}}Client struct { +type {{SERVICE}}V{{VERSION}}Client struct { client *{{GRPC_PACKAGE}}.{{SERVICE}}Client } diff --git a/templates/client_method.go.tpl b/templates/client_method.go.tpl index eb5ae4a..40eee5d 100644 --- a/templates/client_method.go.tpl +++ b/templates/client_method.go.tpl @@ -14,11 +14,11 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" ) -func (s {{SERVICE}}Client) Call(ctx context.Context, requestIntf protoreflect.ProtoMessage, opts ...grpc.CallOption) (protoreflect.ProtoMessage, types.MessageType, error) { - request, ok := requestIntf.(*{{TYPE_PACKAGE}}.{{REQUEST}})) +func (s {{SERVICE}}V{{VERSION}}Client) Call(ctx context.Context, requestIntf protoreflect.ProtoMessage, opts ...grpc.CallOption) (protoreflect.ProtoMessage, types.MessageType, error) { + request, ok := requestIntf.(*{{TYPE_PACKAGE}}.{{REQUEST}}) if !ok { return nil, {{SERVICE}}V{{VERSION}}Response, fmt.Errorf("invalid request type") } - response, err := (*s.client).{{METHOD}})(ctx, request, opts...) + response, err := (*s.client).{{METHOD}}(ctx, request, opts...) return response, {{SERVICE}}V{{VERSION}}Response, err }