Repository: grpc/grpc-go
File: internal/xds/clients/xdsclient/clientimpl_watchers.go (Go)

Code before:

	"google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource"
)

// wrappingWatcher is a wrapper around an xdsresource.ResourceWatcher that adds
// the node ID to the error messages reported to the watcher.
type wrappingWatcher struct {
	ResourceWatcher
	nodeID string
}

func (w *wrappingWatcher) AmbientError(err error, done func()) {
	w.ResourceWatcher.AmbientError(fmt.Errorf("[xDS node id: %v]: %w", w.nodeID, err), done)
}

func (w *wrappingWatcher) ResourceError(err error, done func()) {
	w.ResourceWatcher.ResourceError(fmt.Errorf("[xDS node id: %v]: %w", w.nodeID, err), done)
}

// WatchResource starts watching the specified resource.
//
// typeURL specifies the resource type implementation to use. if there is no
// resource type implementation for the given typeURL, or if authority is not
// found for the resource name, no watch is started and a no-op cancel function
// is returned. See the ResourceTypes field in the Config struct used to create
// the XDSClient.
//
// The returned function cancels the watch and prevents future calls to the
// watcher.
func (c *XDSClient) WatchResource(typeURL, resourceName string, watcher ResourceWatcher) (cancel func()) {
	// Return early if the client is already closed.
	if c.done.HasFired() {
		logger.Warningf("Watch registered for type %q, but client is closed", typeURL)
		return func() {}
	}

	watcher = &wrappingWatcher{
		ResourceWatcher: watcher,
		nodeID:          c.config.Node.ID,
	}

	rType, ok := c.config.ResourceTypes[typeURL]
	if !ok {
		logger.Warningf("ResourceType implementation for resource type url %v is not found", rType.TypeURL)
		c.serializer.TrySchedule(func(context.Context) {
			watcher.ResourceError(fmt.Errorf("ResourceType implementation for resource type url %v is not found", rType.TypeURL), func() {})
		})
		return func() {}
	}

	n := xdsresource.ParseName(resourceName)

Review comment (bug):
How about:

```
// WatchResource starts watching the specified resource.
//
// The watch fails to start if:
//  - There is no ResourceType implementation for the given typeURL in the
//    ResourceTypes field of the Config struct used to create the XDSClient.
//  - The provided resourceName contains an authority that is not present in the
//    Authorities field of the Config struct.
//
// The returned function cancels the watch and prevents future calls to the
// watcher.
```

Code after:

	"google.golang.org/grpc/internal/xds/clients/xdsclient/internal/xdsresource"
)

// wrappingWatcher is a wrapper around an xdsresource.ResourceWatcher that adds
// the node ID to the error messages reported to the watcher.
type wrappingWatcher struct {
	ResourceWatcher
	nodeID string
}

func (w *wrappingWatcher) AmbientError(err error, done func()) {
	w.ResourceWatcher.AmbientError(fmt.Errorf("[xDS node id: %v]: %w", w.nodeID, err), done)
}

func (w *wrappingWatcher) ResourceError(err error, done func()) {
	w.ResourceWatcher.ResourceError(fmt.Errorf("[xDS node id: %v]: %w", w.nodeID, err), done)
}

// WatchResource starts watching the specified resource.
//
// The watch fails to start if:
//   - There is no ResourceType implementation for the given typeURL in the
//     ResourceTypes field of the Config struct used to create the XDSClient.
//   - The provided resourceName contains an authority that is not present in the
//     Authorities field.
//
// The returned function cancels the watch and prevents future calls to the
// watcher.
func (c *XDSClient) WatchResource(typeURL, resourceName string, watcher ResourceWatcher) (cancel func()) {
	// Return early if the client is already closed.
	if c.done.HasFired() {
		logger.Warningf("Watch registered for type %q, but client is closed", typeURL)
		return func() {}
	}

	watcher = &wrappingWatcher{
		ResourceWatcher: watcher,
		nodeID:          c.config.Node.ID,
	}

	rType, ok := c.config.ResourceTypes[typeURL]
	if !ok {
		logger.Warningf("ResourceType implementation for resource type url %q is not found", rType.TypeURL)
		c.serializer.TrySchedule(func(context.Context) {
			watcher.ResourceError(fmt.Errorf("no ResourceType implementation found for typeURL %q", rType.TypeURL), func() {})
		})
		return func() {}
	}

	n := xdsresource.ParseName(resourceName)