blob: 82fcc2e35fd4a8c0442ef10e00591d751ef6f149 [file] [log] [blame]
Abhay Kumara2ae5992025-11-10 14:02:24 +00001/*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19// Package manual defines a resolver that can be used to manually send resolved
20// addresses to ClientConn.
21package manual
22
23import (
24 "sync"
25
26 "google.golang.org/grpc/resolver"
27)
28
29// NewBuilderWithScheme creates a new manual resolver builder with the given
30// scheme. Every instance of the manual resolver may only ever be used with a
31// single grpc.ClientConn. Otherwise, bad things will happen.
32func NewBuilderWithScheme(scheme string) *Resolver {
33 return &Resolver{
34 BuildCallback: func(resolver.Target, resolver.ClientConn, resolver.BuildOptions) {},
35 UpdateStateCallback: func(error) {},
36 ResolveNowCallback: func(resolver.ResolveNowOptions) {},
37 CloseCallback: func() {},
38 scheme: scheme,
39 }
40}
41
42// Resolver is also a resolver builder.
43// It's build() function always returns itself.
44type Resolver struct {
45 // BuildCallback is called when the Build method is called. Must not be
46 // nil. Must not be changed after the resolver may be built.
47 BuildCallback func(resolver.Target, resolver.ClientConn, resolver.BuildOptions)
48 // UpdateStateCallback is called when the UpdateState method is called on
49 // the resolver. The value passed as argument to this callback is the value
50 // returned by the resolver.ClientConn. Must not be nil. Must not be
51 // changed after the resolver may be built.
52 UpdateStateCallback func(err error)
53 // ResolveNowCallback is called when the ResolveNow method is called on the
54 // resolver. Must not be nil. Must not be changed after the resolver may
55 // be built.
56 ResolveNowCallback func(resolver.ResolveNowOptions)
57 // CloseCallback is called when the Close method is called. Must not be
58 // nil. Must not be changed after the resolver may be built.
59 CloseCallback func()
60 scheme string
61
62 // Fields actually belong to the resolver.
63 // Guards access to below fields.
64 mu sync.Mutex
65 cc resolver.ClientConn
66 // Storing the most recent state update makes this resolver resilient to
67 // restarts, which is possible with channel idleness.
68 lastSeenState *resolver.State
69}
70
71// InitialState adds initial state to the resolver so that UpdateState doesn't
72// need to be explicitly called after Dial.
73func (r *Resolver) InitialState(s resolver.State) {
74 r.lastSeenState = &s
75}
76
77// Build returns itself for Resolver, because it's both a builder and a resolver.
78func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
79 r.mu.Lock()
80 defer r.mu.Unlock()
81 // Call BuildCallback after locking to avoid a race when UpdateState or CC
82 // is called before Build returns.
83 r.BuildCallback(target, cc, opts)
84 r.cc = cc
85 if r.lastSeenState != nil {
86 err := r.cc.UpdateState(*r.lastSeenState)
87 go r.UpdateStateCallback(err)
88 }
89 return r, nil
90}
91
92// Scheme returns the manual resolver's scheme.
93func (r *Resolver) Scheme() string {
94 return r.scheme
95}
96
97// ResolveNow is a noop for Resolver.
98func (r *Resolver) ResolveNow(o resolver.ResolveNowOptions) {
99 r.ResolveNowCallback(o)
100}
101
102// Close is a noop for Resolver.
103func (r *Resolver) Close() {
104 r.CloseCallback()
105}
106
107// UpdateState calls UpdateState(s) on the channel. If the resolver has not
108// been Built before, this instead sets the initial state of the resolver, like
109// InitialState.
110func (r *Resolver) UpdateState(s resolver.State) {
111 r.mu.Lock()
112 defer r.mu.Unlock()
113 r.lastSeenState = &s
114 if r.cc == nil {
115 return
116 }
117 err := r.cc.UpdateState(s)
118 r.UpdateStateCallback(err)
119}
120
121// CC returns r's ClientConn when r was last Built. Panics if the resolver has
122// not been Built before.
123func (r *Resolver) CC() resolver.ClientConn {
124 r.mu.Lock()
125 defer r.mu.Unlock()
126 if r.cc == nil {
127 panic("Manual resolver instance has not yet been built.")
128 }
129 return r.cc
130}