diff --git a/.idea/Dealer.iml b/.idea/Nexus.iml similarity index 100% rename from .idea/Dealer.iml rename to .idea/Nexus.iml diff --git a/.idea/modules.xml b/.idea/modules.xml index 39f6e96..1f748ad 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,7 @@ - + \ No newline at end of file diff --git a/pkg/directory/command.go b/pkg/directory/command.go new file mode 100644 index 0000000..cbe6732 --- /dev/null +++ b/pkg/directory/command.go @@ -0,0 +1,22 @@ +package directory + +const ( + CommandMethodGet = "get" + CommandMethodPut = "put" + CommandMethodPatch = "patch" + CommandMethodPost = "post" + CommandMethodDelete = "delete" +) + +type Command struct { + // The unique identifier of the command, different method command can hold the same command id + ID string `json:"id"` + // The method of the command, such as get, post, others; inspired by RESTful design + Method string `json:"method"` + // The tags of the command will be used to invoke the pre-command middlewares and post-command middlewares + Tags []string `json:"tags"` + // The implementation of the command, the handler is the service that will be invoked + Handler []*ServiceInstance `json:"handler"` + + robinIndex uint +} diff --git a/pkg/directory/command_mapping.go b/pkg/directory/command_mapping.go new file mode 100644 index 0000000..881a3a4 --- /dev/null +++ b/pkg/directory/command_mapping.go @@ -0,0 +1,62 @@ +package directory + +import ( + "github.com/samber/lo" + "sync" +) + +// In commands, we use the map and the mutex because it is usually read and only sometimes write +var commandDirectory = make(map[string]*Command) +var commandDirectoryMutex sync.Mutex + +func GetCommandKey(id, method string) string { + return id + ":" + method +} + +func AddCommand(id, method string, tags []string, handler *ServiceInstance) { + commandDirectoryMutex.Lock() + defer commandDirectoryMutex.Unlock() + + ky := GetCommandKey(id, method) + if _, ok := commandDirectory[id]; !ok { + commandDirectory[id] = &Command{ + ID: id, + Method: method, + Tags: tags, + Handler: []*ServiceInstance{handler}, + } + } else { + commandDirectory[ky].Handler = append(commandDirectory[ky].Handler, handler) + commandDirectory[ky].Tags = lo.Uniq(append(commandDirectory[ky].Tags, tags...)) + } + + commandDirectory[ky].Handler = lo.UniqBy(commandDirectory[ky].Handler, func(item *ServiceInstance) string { + return item.ID + }) +} + +func GetCommandHandler(id, method string) *ServiceInstance { + commandDirectoryMutex.Lock() + defer commandDirectoryMutex.Unlock() + + ky := GetCommandKey(id, method) + if val, ok := commandDirectory[ky]; ok { + if len(val.Handler) == 0 { + return nil + } + + idx := val.robinIndex % uint(len(val.Handler)) + val.robinIndex = idx + 1 + return val.Handler[idx] + } + + return nil +} + +func RemoveCommand(id, method string) { + commandDirectoryMutex.Lock() + defer commandDirectoryMutex.Unlock() + + ky := GetCommandKey(id, method) + delete(commandDirectory, ky) +} diff --git a/pkg/directory/command_rpc.go b/pkg/directory/command_rpc.go new file mode 100644 index 0000000..356001d --- /dev/null +++ b/pkg/directory/command_rpc.go @@ -0,0 +1,89 @@ +package directory + +import ( + "context" + "git.solsynth.dev/hypernet/nexus/pkg/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "io" + "time" +) + +type CommandRpcServer struct { + proto.UnimplementedCommandControllerServer +} + +func (c CommandRpcServer) AddCommand(ctx context.Context, info *proto.CommandInfo) (*proto.AddCommandResponse, error) { + clientId, err := GetClientId(ctx) + if err != nil { + return nil, err + } + + service := GetServiceInstanceByType(clientId) + if service == nil { + return nil, status.Errorf(codes.NotFound, "service not found") + } + + AddCommand(info.GetId(), info.GetMethod(), info.GetTags(), service) + return &proto.AddCommandResponse{ + IsSuccess: true, + }, nil +} + +func (c CommandRpcServer) RemoveCommand(ctx context.Context, request *proto.CommandLookupRequest) (*proto.RemoveCommandResponse, error) { + RemoveCommand(request.GetId(), request.GetMethod()) + return &proto.RemoveCommandResponse{ + IsSuccess: true, + }, nil +} + +func (c CommandRpcServer) SendCommand(ctx context.Context, argument *proto.CommandArgument) (*proto.CommandReturn, error) { + id := argument.GetCommand() + method := argument.GetMethod() + + handler := GetCommandHandler(id, method) + if handler == nil { + return nil, status.Errorf(codes.NotFound, "command not found") + } + + conn, err := handler.GetGrpcConn() + if err != nil { + return nil, status.Errorf(codes.Unavailable, "service unavailable") + } + + contx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + + return proto.NewCommandControllerClient(conn).SendCommand(contx, argument) +} + +func (c CommandRpcServer) SendStreamCommand(g grpc.BidiStreamingServer[proto.CommandArgument, proto.CommandReturn]) error { + for { + pck, err := g.Recv() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + + id := pck.GetCommand() + method := pck.GetMethod() + + handler := GetCommandHandler(id, method) + if handler == nil { + return status.Errorf(codes.NotFound, "command not found") + } + + conn, err := handler.GetGrpcConn() + + contx, cancel := context.WithTimeout(context.Background(), time.Second*10) + result, _ := proto.NewCommandControllerClient(conn).SendCommand(contx, pck) + cancel() + + _ = g.Send(&proto.CommandReturn{ + Status: result.Status, + Payload: result.Payload, + }) + } +} diff --git a/pkg/directory/exts.go b/pkg/directory/exts.go new file mode 100644 index 0000000..d76008d --- /dev/null +++ b/pkg/directory/exts.go @@ -0,0 +1,20 @@ +package directory + +import ( + "context" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +func GetClientId(ctx context.Context) (string, error) { + var clientId string + if md, ok := metadata.FromIncomingContext(ctx); !ok { + return clientId, status.Errorf(codes.InvalidArgument, "missing metadata") + } else if val, ok := md["client_id"]; !ok || len(val) == 0 { + return clientId, status.Errorf(codes.Unauthenticated, "missing client_id in metadata") + } else { + clientId = val[0] + } + return clientId, nil +} diff --git a/pkg/directory/models.go b/pkg/directory/service.go similarity index 100% rename from pkg/directory/models.go rename to pkg/directory/service.go diff --git a/pkg/directory/services.go b/pkg/directory/service_mapping.go similarity index 93% rename from pkg/directory/services.go rename to pkg/directory/service_mapping.go index 17197b9..6d55a16 100644 --- a/pkg/directory/services.go +++ b/pkg/directory/service_mapping.go @@ -4,6 +4,7 @@ import ( "sync" ) +// In services, we use sync.Map because it will be both often read and write var serviceDirectory sync.Map func GetServiceInstance(id string) *ServiceInstance { diff --git a/pkg/directory/rpc.go b/pkg/directory/service_rpc.go similarity index 55% rename from pkg/directory/rpc.go rename to pkg/directory/service_rpc.go index c2533e2..55eb333 100644 --- a/pkg/directory/rpc.go +++ b/pkg/directory/service_rpc.go @@ -3,17 +3,19 @@ package directory import ( "context" "fmt" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "git.solsynth.dev/hypernet/nexus/pkg/proto" "github.com/rs/zerolog/log" "github.com/samber/lo" ) -type DirectoryRpcServer struct { +type ServiceRpcServer struct { proto.UnimplementedServiceDirectoryServer } -func convertServiceToInfo(in *ServiceInstance) *proto.ServiceInfo { +func instantiationService(in *ServiceInstance) *proto.ServiceInfo { if in == nil { return nil } @@ -26,23 +28,23 @@ func convertServiceToInfo(in *ServiceInstance) *proto.ServiceInfo { } } -func (v *DirectoryRpcServer) GetService(ctx context.Context, request *proto.GetServiceRequest) (*proto.GetServiceResponse, error) { +func (v *ServiceRpcServer) GetService(ctx context.Context, request *proto.GetServiceRequest) (*proto.GetServiceResponse, error) { if request.Id != nil { out := GetServiceInstance(request.GetId()) return &proto.GetServiceResponse{ - Data: convertServiceToInfo(out), + Data: instantiationService(out), }, nil } if request.Type != nil { out := GetServiceInstanceByType(request.GetType()) return &proto.GetServiceResponse{ - Data: convertServiceToInfo(out), + Data: instantiationService(out), }, nil } return nil, fmt.Errorf("no filter condition is provided") } -func (v *DirectoryRpcServer) ListService(ctx context.Context, request *proto.ListServiceRequest) (*proto.ListServiceResponse, error) { +func (v *ServiceRpcServer) ListService(ctx context.Context, request *proto.ListServiceRequest) (*proto.ListServiceResponse, error) { var out []*ServiceInstance if request.Type != nil { out = ListServiceInstanceByType(request.GetType()) @@ -51,27 +53,36 @@ func (v *DirectoryRpcServer) ListService(ctx context.Context, request *proto.Lis } return &proto.ListServiceResponse{ Data: lo.Map(out, func(item *ServiceInstance, index int) *proto.ServiceInfo { - return convertServiceToInfo(item) + return instantiationService(item) }), }, nil } -func (v *DirectoryRpcServer) AddService(ctx context.Context, info *proto.ServiceInfo) (*proto.AddServiceResponse, error) { +func (v *ServiceRpcServer) AddService(ctx context.Context, info *proto.ServiceInfo) (*proto.AddServiceResponse, error) { + clientId, err := GetClientId(ctx) + if err != nil { + return nil, err + } + + if info.GetId() != clientId { + return nil, status.Errorf(codes.InvalidArgument, "client_id mismatch in metadata") + } + in := &ServiceInstance{ - ID: info.GetId(), + ID: clientId, Type: info.GetType(), Label: info.GetLabel(), GrpcAddr: info.GetGrpcAddr(), HttpAddr: info.HttpAddr, } AddServiceInstance(in) - log.Info().Str("id", info.GetId()).Str("label", info.GetLabel()).Msg("New service added.") + log.Info().Str("id", clientId).Str("label", info.GetLabel()).Msg("New service added.") return &proto.AddServiceResponse{ IsSuccess: true, }, nil } -func (v *DirectoryRpcServer) RemoveService(ctx context.Context, request *proto.RemoveServiceRequest) (*proto.RemoveServiceResponse, error) { +func (v *ServiceRpcServer) RemoveService(ctx context.Context, request *proto.RemoveServiceRequest) (*proto.RemoveServiceResponse, error) { RemoveServiceInstance(request.GetId()) log.Info().Str("id", request.GetId()).Msg("A service removed.") return &proto.RemoveServiceResponse{ diff --git a/pkg/http/api/index.go b/pkg/http/api/index.go index dd6467a..6e66f16 100644 --- a/pkg/http/api/index.go +++ b/pkg/http/api/index.go @@ -6,6 +6,7 @@ import ( ) func MapAPIs(app *fiber.App) { + // Some built-in public-accessible APIs wellKnown := app.Group("/.well-known").Name("Well Known") { wellKnown.Get("/", func(c *fiber.Ctx) error { @@ -15,19 +16,13 @@ func MapAPIs(app *fiber.App) { wellKnown.Get("/directory/services", listExistsService) } + // Common websocket gateway + app.Use(func(c *fiber.Ctx) error { + /*if err := exts.EnsureAuthenticated(c); err != nil { + return err + }*/ + return c.Next() + }).Get("/ws", websocket.New(listenWebsocket)) + app.All("/cgi/:service/*", forwardServiceRequest) - - api := app.Group("/api").Name("API") - { - api.Use(func(c *fiber.Ctx) error { - /*if err := exts.EnsureAuthenticated(c); err != nil { - return err - }*/ - return c.Next() - }).Get("/ws", websocket.New(listenWebsocket)) - - api.All("/*", func(c *fiber.Ctx) error { - return fiber.ErrNotFound - }) - } } diff --git a/pkg/internal/grpc/server.go b/pkg/internal/grpc/server.go index 82ce2f0..41579c4 100644 --- a/pkg/internal/grpc/server.go +++ b/pkg/internal/grpc/server.go @@ -25,7 +25,8 @@ func NewServer() *GrpcServer { srv: grpc.NewServer(), } - proto.RegisterServiceDirectoryServer(server.srv, &directory.DirectoryRpcServer{}) + proto.RegisterServiceDirectoryServer(server.srv, &directory.ServiceRpcServer{}) + proto.RegisterCommandControllerServer(server.srv, &directory.CommandRpcServer{}) proto.RegisterStreamControllerServer(server.srv, server) health.RegisterHealthServer(server.srv, server) diff --git a/pkg/internal/services/pusher_conn.go b/pkg/internal/services/pusher_conn.go deleted file mode 100644 index 0b52a28..0000000 --- a/pkg/internal/services/pusher_conn.go +++ /dev/null @@ -1,43 +0,0 @@ -package services - -import ( - "context" - firebase "firebase.google.com/go" - "github.com/sideshow/apns2" - "github.com/sideshow/apns2/token" - "github.com/spf13/viper" - "google.golang.org/api/option" -) - -// ExtFire is a Firebase App client -var ExtFire *firebase.App - -func SetupFirebase() error { - opt := option.WithCredentialsFile(viper.GetString("firebase_credentials")) - app, err := firebase.NewApp(context.Background(), nil, opt) - if err != nil { - return err - } else { - ExtFire = app - } - - return nil -} - -// ExtAPNS is an Apple Push Notification Services client -var ExtAPNS *apns2.Client - -func SetupAPNS() error { - authKey, err := token.AuthKeyFromFile(viper.GetString("apns_credentials")) - if err != nil { - return err - } - - ExtAPNS = apns2.NewTokenClient(&token.Token{ - AuthKey: authKey, - KeyID: viper.GetString("apns_credentials_key"), - TeamID: viper.GetString("apns_credentials_team"), - }).Production() - - return nil -} diff --git a/pkg/main.go b/pkg/main.go index b82c375..a9a417b 100644 --- a/pkg/main.go +++ b/pkg/main.go @@ -5,8 +5,6 @@ import ( "os/signal" "syscall" - "git.solsynth.dev/hypernet/nexus/pkg/internal/services" - server "git.solsynth.dev/hypernet/nexus/pkg/http" pkg "git.solsynth.dev/hypernet/nexus/pkg/internal" "git.solsynth.dev/hypernet/nexus/pkg/internal/grpc" @@ -34,14 +32,6 @@ func main() { log.Panic().Err(err).Msg("An error occurred when loading settings.") } - // Set up external services - if err := services.SetupFirebase(); err != nil { - log.Warn().Err(err).Msg("An error occurred when setup firebase, firebase notification push is unavailable...") - } - if err := services.SetupAPNS(); err != nil { - log.Warn().Err(err).Msg("An error occurred when setup APNs, apple notification push is unavailable...") - } - // Server go server.NewServer().Listen() diff --git a/pkg/proto/command.pb.go b/pkg/proto/command.pb.go new file mode 100644 index 0000000..00fb742 --- /dev/null +++ b/pkg/proto/command.pb.go @@ -0,0 +1,457 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.35.1 +// protoc v5.28.2 +// source: command.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type CommandInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` + Tags []string `protobuf:"bytes,3,rep,name=tags,proto3" json:"tags,omitempty"` +} + +func (x *CommandInfo) Reset() { + *x = CommandInfo{} + mi := &file_command_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandInfo) ProtoMessage() {} + +func (x *CommandInfo) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandInfo.ProtoReflect.Descriptor instead. +func (*CommandInfo) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{0} +} + +func (x *CommandInfo) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *CommandInfo) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *CommandInfo) GetTags() []string { + if x != nil { + return x.Tags + } + return nil +} + +type CommandLookupRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` +} + +func (x *CommandLookupRequest) Reset() { + *x = CommandLookupRequest{} + mi := &file_command_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandLookupRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandLookupRequest) ProtoMessage() {} + +func (x *CommandLookupRequest) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandLookupRequest.ProtoReflect.Descriptor instead. +func (*CommandLookupRequest) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{1} +} + +func (x *CommandLookupRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *CommandLookupRequest) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +type AddCommandResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IsSuccess bool `protobuf:"varint,1,opt,name=is_success,json=isSuccess,proto3" json:"is_success,omitempty"` +} + +func (x *AddCommandResponse) Reset() { + *x = AddCommandResponse{} + mi := &file_command_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *AddCommandResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddCommandResponse) ProtoMessage() {} + +func (x *AddCommandResponse) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddCommandResponse.ProtoReflect.Descriptor instead. +func (*AddCommandResponse) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{2} +} + +func (x *AddCommandResponse) GetIsSuccess() bool { + if x != nil { + return x.IsSuccess + } + return false +} + +type RemoveCommandResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + IsSuccess bool `protobuf:"varint,1,opt,name=is_success,json=isSuccess,proto3" json:"is_success,omitempty"` +} + +func (x *RemoveCommandResponse) Reset() { + *x = RemoveCommandResponse{} + mi := &file_command_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RemoveCommandResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveCommandResponse) ProtoMessage() {} + +func (x *RemoveCommandResponse) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[3] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveCommandResponse.ProtoReflect.Descriptor instead. +func (*RemoveCommandResponse) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{3} +} + +func (x *RemoveCommandResponse) GetIsSuccess() bool { + if x != nil { + return x.IsSuccess + } + return false +} + +type CommandArgument struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Command string `protobuf:"bytes,1,opt,name=command,proto3" json:"command,omitempty"` + Method string `protobuf:"bytes,2,opt,name=method,proto3" json:"method,omitempty"` + Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3,oneof" json:"payload,omitempty"` +} + +func (x *CommandArgument) Reset() { + *x = CommandArgument{} + mi := &file_command_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandArgument) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandArgument) ProtoMessage() {} + +func (x *CommandArgument) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[4] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandArgument.ProtoReflect.Descriptor instead. +func (*CommandArgument) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{4} +} + +func (x *CommandArgument) GetCommand() string { + if x != nil { + return x.Command + } + return "" +} + +func (x *CommandArgument) GetMethod() string { + if x != nil { + return x.Method + } + return "" +} + +func (x *CommandArgument) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +type CommandReturn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Status int32 `protobuf:"varint,1,opt,name=status,proto3" json:"status,omitempty"` + Payload []byte `protobuf:"bytes,2,opt,name=payload,proto3,oneof" json:"payload,omitempty"` +} + +func (x *CommandReturn) Reset() { + *x = CommandReturn{} + mi := &file_command_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CommandReturn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CommandReturn) ProtoMessage() {} + +func (x *CommandReturn) ProtoReflect() protoreflect.Message { + mi := &file_command_proto_msgTypes[5] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CommandReturn.ProtoReflect.Descriptor instead. +func (*CommandReturn) Descriptor() ([]byte, []int) { + return file_command_proto_rawDescGZIP(), []int{5} +} + +func (x *CommandReturn) GetStatus() int32 { + if x != nil { + return x.Status + } + return 0 +} + +func (x *CommandReturn) GetPayload() []byte { + if x != nil { + return x.Payload + } + return nil +} + +var File_command_proto protoreflect.FileDescriptor + +var file_command_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x49, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, + 0x73, 0x22, 0x3e, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, + 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x22, 0x33, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x73, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, + 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x36, 0x0a, 0x15, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x69, 0x73, 0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x6e, + 0x0a, 0x0f, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6d, + 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x88, + 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x52, + 0x0a, 0x0d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, + 0x6f, 0x61, 0x64, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x32, 0xa8, 0x02, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, 0x0d, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x4c, 0x6f, 0x6f, 0x6b, 0x75, 0x70, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x0b, 0x53, 0x65, 0x6e, 0x64, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x14, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x74, 0x75, + 0x72, 0x6e, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, + 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x52, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x09, 0x5a, + 0x07, 0x2e, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_command_proto_rawDescOnce sync.Once + file_command_proto_rawDescData = file_command_proto_rawDesc +) + +func file_command_proto_rawDescGZIP() []byte { + file_command_proto_rawDescOnce.Do(func() { + file_command_proto_rawDescData = protoimpl.X.CompressGZIP(file_command_proto_rawDescData) + }) + return file_command_proto_rawDescData +} + +var file_command_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_command_proto_goTypes = []any{ + (*CommandInfo)(nil), // 0: proto.CommandInfo + (*CommandLookupRequest)(nil), // 1: proto.CommandLookupRequest + (*AddCommandResponse)(nil), // 2: proto.AddCommandResponse + (*RemoveCommandResponse)(nil), // 3: proto.RemoveCommandResponse + (*CommandArgument)(nil), // 4: proto.CommandArgument + (*CommandReturn)(nil), // 5: proto.CommandReturn +} +var file_command_proto_depIdxs = []int32{ + 0, // 0: proto.CommandController.AddCommand:input_type -> proto.CommandInfo + 1, // 1: proto.CommandController.RemoveCommand:input_type -> proto.CommandLookupRequest + 4, // 2: proto.CommandController.SendCommand:input_type -> proto.CommandArgument + 4, // 3: proto.CommandController.SendStreamCommand:input_type -> proto.CommandArgument + 2, // 4: proto.CommandController.AddCommand:output_type -> proto.AddCommandResponse + 3, // 5: proto.CommandController.RemoveCommand:output_type -> proto.RemoveCommandResponse + 5, // 6: proto.CommandController.SendCommand:output_type -> proto.CommandReturn + 5, // 7: proto.CommandController.SendStreamCommand:output_type -> proto.CommandReturn + 4, // [4:8] is the sub-list for method output_type + 0, // [0:4] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_command_proto_init() } +func file_command_proto_init() { + if File_command_proto != nil { + return + } + file_command_proto_msgTypes[4].OneofWrappers = []any{} + file_command_proto_msgTypes[5].OneofWrappers = []any{} + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_command_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_command_proto_goTypes, + DependencyIndexes: file_command_proto_depIdxs, + MessageInfos: file_command_proto_msgTypes, + }.Build() + File_command_proto = out.File + file_command_proto_rawDesc = nil + file_command_proto_goTypes = nil + file_command_proto_depIdxs = nil +} diff --git a/pkg/proto/command.proto b/pkg/proto/command.proto new file mode 100644 index 0000000..c81b50d --- /dev/null +++ b/pkg/proto/command.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +option go_package = ".;proto"; + +package proto; + +service CommandController { + rpc AddCommand(CommandInfo) returns (AddCommandResponse) {} + rpc RemoveCommand(CommandLookupRequest) returns (RemoveCommandResponse) {} + rpc SendCommand(CommandArgument) returns (CommandReturn) {} + rpc SendStreamCommand(stream CommandArgument) returns (stream CommandReturn) {} +} + +message CommandInfo { + string id = 1; + string method = 2; + repeated string tags = 3; +} + +message CommandLookupRequest { + string id = 1; + string method = 2; +} + +message AddCommandResponse { + bool is_success = 1; +} + +message RemoveCommandResponse { + bool is_success = 1; +} + +message CommandArgument { + string command = 1; + string method = 2; + optional bytes payload = 3; +} + +message CommandReturn { + int32 status = 1; + optional bytes payload = 2; +} \ No newline at end of file diff --git a/pkg/proto/command_grpc.pb.go b/pkg/proto/command_grpc.pb.go new file mode 100644 index 0000000..62fb921 --- /dev/null +++ b/pkg/proto/command_grpc.pb.go @@ -0,0 +1,230 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.5.1 +// - protoc v5.28.2 +// source: command.proto + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.64.0 or later. +const _ = grpc.SupportPackageIsVersion9 + +const ( + CommandController_AddCommand_FullMethodName = "/proto.CommandController/AddCommand" + CommandController_RemoveCommand_FullMethodName = "/proto.CommandController/RemoveCommand" + CommandController_SendCommand_FullMethodName = "/proto.CommandController/SendCommand" + CommandController_SendStreamCommand_FullMethodName = "/proto.CommandController/SendStreamCommand" +) + +// CommandControllerClient is the client API for CommandController service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type CommandControllerClient interface { + AddCommand(ctx context.Context, in *CommandInfo, opts ...grpc.CallOption) (*AddCommandResponse, error) + RemoveCommand(ctx context.Context, in *CommandLookupRequest, opts ...grpc.CallOption) (*RemoveCommandResponse, error) + SendCommand(ctx context.Context, in *CommandArgument, opts ...grpc.CallOption) (*CommandReturn, error) + SendStreamCommand(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[CommandArgument, CommandReturn], error) +} + +type commandControllerClient struct { + cc grpc.ClientConnInterface +} + +func NewCommandControllerClient(cc grpc.ClientConnInterface) CommandControllerClient { + return &commandControllerClient{cc} +} + +func (c *commandControllerClient) AddCommand(ctx context.Context, in *CommandInfo, opts ...grpc.CallOption) (*AddCommandResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(AddCommandResponse) + err := c.cc.Invoke(ctx, CommandController_AddCommand_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandControllerClient) RemoveCommand(ctx context.Context, in *CommandLookupRequest, opts ...grpc.CallOption) (*RemoveCommandResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RemoveCommandResponse) + err := c.cc.Invoke(ctx, CommandController_RemoveCommand_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandControllerClient) SendCommand(ctx context.Context, in *CommandArgument, opts ...grpc.CallOption) (*CommandReturn, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(CommandReturn) + err := c.cc.Invoke(ctx, CommandController_SendCommand_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *commandControllerClient) SendStreamCommand(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[CommandArgument, CommandReturn], error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + stream, err := c.cc.NewStream(ctx, &CommandController_ServiceDesc.Streams[0], CommandController_SendStreamCommand_FullMethodName, cOpts...) + if err != nil { + return nil, err + } + x := &grpc.GenericClientStream[CommandArgument, CommandReturn]{ClientStream: stream} + return x, nil +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type CommandController_SendStreamCommandClient = grpc.BidiStreamingClient[CommandArgument, CommandReturn] + +// CommandControllerServer is the server API for CommandController service. +// All implementations must embed UnimplementedCommandControllerServer +// for forward compatibility. +type CommandControllerServer interface { + AddCommand(context.Context, *CommandInfo) (*AddCommandResponse, error) + RemoveCommand(context.Context, *CommandLookupRequest) (*RemoveCommandResponse, error) + SendCommand(context.Context, *CommandArgument) (*CommandReturn, error) + SendStreamCommand(grpc.BidiStreamingServer[CommandArgument, CommandReturn]) error + mustEmbedUnimplementedCommandControllerServer() +} + +// UnimplementedCommandControllerServer must be embedded to have +// forward compatible implementations. +// +// NOTE: this should be embedded by value instead of pointer to avoid a nil +// pointer dereference when methods are called. +type UnimplementedCommandControllerServer struct{} + +func (UnimplementedCommandControllerServer) AddCommand(context.Context, *CommandInfo) (*AddCommandResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddCommand not implemented") +} +func (UnimplementedCommandControllerServer) RemoveCommand(context.Context, *CommandLookupRequest) (*RemoveCommandResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveCommand not implemented") +} +func (UnimplementedCommandControllerServer) SendCommand(context.Context, *CommandArgument) (*CommandReturn, error) { + return nil, status.Errorf(codes.Unimplemented, "method SendCommand not implemented") +} +func (UnimplementedCommandControllerServer) SendStreamCommand(grpc.BidiStreamingServer[CommandArgument, CommandReturn]) error { + return status.Errorf(codes.Unimplemented, "method SendStreamCommand not implemented") +} +func (UnimplementedCommandControllerServer) mustEmbedUnimplementedCommandControllerServer() {} +func (UnimplementedCommandControllerServer) testEmbeddedByValue() {} + +// UnsafeCommandControllerServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to CommandControllerServer will +// result in compilation errors. +type UnsafeCommandControllerServer interface { + mustEmbedUnimplementedCommandControllerServer() +} + +func RegisterCommandControllerServer(s grpc.ServiceRegistrar, srv CommandControllerServer) { + // If the following call pancis, it indicates UnimplementedCommandControllerServer was + // embedded by pointer and is nil. This will cause panics if an + // unimplemented method is ever invoked, so we test this at initialization + // time to prevent it from happening at runtime later due to I/O. + if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { + t.testEmbeddedByValue() + } + s.RegisterService(&CommandController_ServiceDesc, srv) +} + +func _CommandController_AddCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommandInfo) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandControllerServer).AddCommand(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandController_AddCommand_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandControllerServer).AddCommand(ctx, req.(*CommandInfo)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandController_RemoveCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommandLookupRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandControllerServer).RemoveCommand(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandController_RemoveCommand_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandControllerServer).RemoveCommand(ctx, req.(*CommandLookupRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandController_SendCommand_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CommandArgument) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(CommandControllerServer).SendCommand(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: CommandController_SendCommand_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(CommandControllerServer).SendCommand(ctx, req.(*CommandArgument)) + } + return interceptor(ctx, in, info, handler) +} + +func _CommandController_SendStreamCommand_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(CommandControllerServer).SendStreamCommand(&grpc.GenericServerStream[CommandArgument, CommandReturn]{ServerStream: stream}) +} + +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type CommandController_SendStreamCommandServer = grpc.BidiStreamingServer[CommandArgument, CommandReturn] + +// CommandController_ServiceDesc is the grpc.ServiceDesc for CommandController service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var CommandController_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "proto.CommandController", + HandlerType: (*CommandControllerServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddCommand", + Handler: _CommandController_AddCommand_Handler, + }, + { + MethodName: "RemoveCommand", + Handler: _CommandController_RemoveCommand_Handler, + }, + { + MethodName: "SendCommand", + Handler: _CommandController_SendCommand_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "SendStreamCommand", + Handler: _CommandController_SendStreamCommand_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "command.proto", +}