I have some code that receives protobuf messages that is basically duplicated in a couple places so I want to put it into a library. The problem is that the exact protobuf message that's used is different for each set of code.
EDIT: And I don't have the flexiblity of restructuring them.
I'm not entirely sure this is possible to solve without duplicate code in go, but I did make an attempt (below). Am I doing something wrong, or is this not something that's not possible? (Note: This is stripped down code, in the real code the objects have lots of additional fields)
Example.proto:
package testmsg;
enum RepStatus {
DONE_OK = 0;
DONE_ERROR = 1;
}
message ReqHeader {
optional int64 user_id = 1;
}
message RespHeader {
optional RepStatus status = 1;
optional string error_msg = 2;
}
message PostReq {
optional ReqHeader header = 1;
optional bytes post_data = 2;
}
message PostResp {
optional RespHeader header = 1;
}
message StatusReq {
optional ReqHeader header = 1;
optional string id = 2;
}
message StatusRep {
optional RespHeader header = 1;
optional string status = 2;
}
mini-service/service.go:
package miniservice
import "reflect"
import "github.com/golang/protobuf/proto"
import "testmsg"
type MiniService struct {
name string
reqType reflect.Type
repType reflect.Type
}
func NewService(name string, reqPort int, reqType proto.Message, repType proto.Message) *MiniService {
ms := new(MiniService)
ms.name = name
ms.reqType = reflect.TypeOf(reqType)
ms.repType = reflect.TypeOf(repType)
return ms
}
func (ms *MiniService) Handler(msgs []string) (string) {
resp := reflect.New(ms.repType.Elem())
msg := msgs[0]
req := reflect.New(ms.reqType.Elem())
err := proto.Unmarshal([]byte(msg), req)
//add some error handling, or just get set _
resp.Header = &testmsg.RespHeader{}
//Call handler function that is unique per service
//the signature will be something like:
//handleRequest(reqType, respType) & called like:
//handleRequest(req, resp)
resp.Header.Status = testmsg.RepStatus_DONE_OK.Enum()
respMsg, _ := proto.Marshal(resp)
return string(respMsg)
}
testservice.go:
package main
import "github.com/golang/protobuf/proto"
import "testmsg"
import "mylibs/mini-service"
func main() {
//fake out a zmq message
req := &testmsg.PostReq{}
req.Header = &testmsg.ReqHeader{}
req.Header.MessageId = proto.Int64(10)
reqMsg, _ := proto.Marshal(req)
reqMsgs := []string{string(reqMsg)}
ms := miniservice.NewService("tester", 5555, testmsg.PostReq, testmsg.PostResp)
//What will be called when receiving a zmq request
resp := ms.Handler(reqMsgs)
log.Info(resp)
}
When I try to compile I get errors like:
resp.Header undefined (type reflect.Value has no field or method Header)
cannot use resp (type reflect.Value) as type proto.Message in argument to proto.Marshal:
reflect.Value does not implement proto.Message (missing ProtoMessage method)
Which make complete sense since the resp isn't connected to ms.respType.