@@ -54,6 +54,9 @@ export interface ProxyContextValue {
54
54
// then the latency has not been fetched yet. Calculations happen async for each proxy in the list.
55
55
// Refer to the returned report for a given proxy for more information.
56
56
proxyLatencies : ProxyLatencies ;
57
+ // latenciesLoaded is true when the latencies have been initially loaded.
58
+ // Once set to true, it will not be set to false again.
59
+ latenciesLoaded : boolean ;
57
60
// refetchProxyLatencies will trigger refreshing of the proxy latencies. By default the latencies
58
61
// are loaded once.
59
62
refetchProxyLatencies : ( ) => Date ;
@@ -122,8 +125,11 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
122
125
123
126
// Every time we get a new proxiesResponse, update the latency check
124
127
// to each workspace proxy.
125
- const { proxyLatencies, refetch : refetchProxyLatencies } =
126
- useProxyLatency ( proxiesResp ) ;
128
+ const {
129
+ proxyLatencies,
130
+ refetch : refetchProxyLatencies ,
131
+ loaded : latenciesLoaded ,
132
+ } = useProxyLatency ( proxiesResp ) ;
127
133
128
134
// updateProxy is a helper function that when called will
129
135
// update the proxy being used.
@@ -136,7 +142,8 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
136
142
loadUserSelectedProxy ( ) ,
137
143
proxyLatencies ,
138
144
// Do not auto select based on latencies, as inconsistent latencies can cause this
139
- // to behave poorly.
145
+ // to change on each call. updateProxy should be stable when selecting a proxy to
146
+ // prevent flickering.
140
147
false ,
141
148
) ,
142
149
) ;
@@ -149,6 +156,34 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
149
156
updateProxy ( ) ;
150
157
} , [ proxiesResp , proxyLatencies ] ) ;
151
158
159
+ // This useEffect will auto select the best proxy if the user has not selected one.
160
+ // It must wait until all latencies are loaded to select based on latency. This does mean
161
+ // the first time a user loads the page, the proxy will "flicker" to the best proxy.
162
+ //
163
+ // Once the page is loaded, or the user selects a proxy, this will not run again.
164
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Only update if the source data changes
165
+ useEffect ( ( ) => {
166
+ if ( loadUserSelectedProxy ( ) !== undefined ) {
167
+ return ; // User has selected a proxy, do not auto select.
168
+ }
169
+ if ( ! latenciesLoaded ) {
170
+ // Wait until the latencies are loaded first.
171
+ return ;
172
+ }
173
+
174
+ const best = getPreferredProxy (
175
+ proxiesResp ?? [ ] ,
176
+ loadUserSelectedProxy ( ) ,
177
+ proxyLatencies ,
178
+ true ,
179
+ ) ;
180
+
181
+ if ( best ?. proxy ) {
182
+ saveUserSelectedProxy ( best . proxy ) ;
183
+ updateProxy ( ) ;
184
+ }
185
+ } , [ latenciesLoaded , proxiesResp , proxyLatencies ] ) ;
186
+
152
187
return (
153
188
< ProxyContext . Provider
154
189
value = { {
@@ -157,6 +192,7 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
157
192
userProxy : userSavedProxy ,
158
193
proxy : proxy ,
159
194
proxies : proxiesResp ,
195
+ latenciesLoaded : latenciesLoaded ,
160
196
isLoading : proxiesLoading ,
161
197
isFetched : proxiesFetched ,
162
198
error : proxiesError ,
@@ -214,12 +250,12 @@ export const getPreferredProxy = (
214
250
215
251
// If no proxy is selected, or the selected proxy is unhealthy default to the primary proxy.
216
252
if ( ! selectedProxy || ! selectedProxy . healthy ) {
217
- // By default, use the primary proxy.
253
+ // Default to the primary proxy
218
254
selectedProxy = proxies . find ( ( proxy ) => proxy . name === "primary" ) ;
219
255
220
256
// If we have latencies, then attempt to use the best proxy by latency instead.
221
257
const best = selectByLatency ( proxies , latencies ) ;
222
- if ( autoSelectBasedOnLatency && best ) {
258
+ if ( autoSelectBasedOnLatency && best !== undefined ) {
223
259
selectedProxy = best ;
224
260
}
225
261
}
0 commit comments