diff --git a/module/modmanager/manager.go b/module/modmanager/manager.go index 408c060e0f9..87f9fe9826e 100644 --- a/module/modmanager/manager.go +++ b/module/modmanager/manager.go @@ -830,9 +830,9 @@ func (mgr *Manager) newOnUnexpectedExitHandler(mod *module) func(exitCode int) b if orphanedResourceNames := mgr.attemptRestart(mgr.restartCtx, mod); orphanedResourceNames != nil { if mgr.removeOrphanedResources != nil { mgr.removeOrphanedResources(mgr.restartCtx, orphanedResourceNames) - rNames := make([]string, len(orphanedResourceNames)) - for idx, rName := range orphanedResourceNames { - rNames[idx] = rName.String() + rNames := make([]string, 0, len(orphanedResourceNames)) + for _, rName := range orphanedResourceNames { + rNames = append(rNames, rName.String()) } mgr.logger.Debugw("Removed resources after failed module restart", "module", mod.cfg.Name, "resources", rNames) } diff --git a/robot/robot.go b/robot/robot.go index 5bd9ccf13a3..6c678b43341 100644 --- a/robot/robot.go +++ b/robot/robot.go @@ -258,8 +258,8 @@ func TypeAndMethodDescFromMethod(r Robot, method string) (*resource.RPCAPI, *des if len(methodParts) != 3 { return nil, nil, grpc.UnimplementedError } - protoSvc := methodParts[1] - protoMethod := methodParts[2] + protoSvc := methodParts[1] // e.g. viam.component.arm.v1.ArmService + protoMethod := methodParts[2] // e.g. DoCommand var foundType *resource.RPCAPI for _, resAPI := range r.ResourceRPCAPIs() { diff --git a/robot/web/web.go b/robot/web/web.go index d778b77ff34..4c5a46d7fe6 100644 --- a/robot/web/web.go +++ b/robot/web/web.go @@ -927,7 +927,12 @@ func (svc *webService) initMux(options weboptions.Options) (*goji.Mux, error) { return mux, nil } +// foreignServiceHandler is a bidi-streaming RPC service handler to support custom APIs. +// It is invoked instead of returning the "unimplemented" gRPC error whenever a request is received for +// an unregistered service or method. These method could be registered on a remote viam-server or a module server +// so this handler will attempt to route the request to the correct next node in the chain. func (svc *webService) foreignServiceHandler(srv interface{}, stream googlegrpc.ServerStream) error { + // method will be in the form of PackageName.ServiceName/MethodName method, ok := googlegrpc.MethodFromServerStream(stream) if !ok { return grpc.UnimplementedError @@ -939,10 +944,15 @@ func (svc *webService) foreignServiceHandler(srv interface{}, stream googlegrpc. firstMsg := dynamic.NewMessage(methodDesc.GetInputType()) + // The stream blocks until it receives a message and attempts to deserialize + // the message into firstMsg - it will error out if the received message cannot + // be marshalled into the expected type. if err := stream.RecvMsg(firstMsg); err != nil { return err } + // We expect each message to contain a "name" argument which will allow us to route + // the message towards the correct destination. resource, fqName, err := robot.ResourceFromProtoMessage(svc.r, firstMsg, subType.API) if err != nil { svc.logger.Errorw("unable to route foreign message", "error", err)