feat: add region querying to pre-fetched html (#8077)

This commit is contained in:
Kyle Carberry
2023-06-19 11:23:26 -05:00
committed by GitHub
parent e083cbca6a
commit f444100aa6
5 changed files with 86 additions and 25 deletions
+1
View File
@@ -67,6 +67,7 @@ func New(ctx context.Context, options *Options) (_ *API, err error) {
api.AGPL.Options.SetUserGroups = api.setUserGroups
api.AGPL.SiteHandler.AppearanceFetcher = api.fetchAppearanceConfig
api.AGPL.SiteHandler.RegionsFetcher = api.fetchRegions
oauthConfigs := &httpmw.OAuth2Configs{
Github: options.GithubOAuth2Config,
+15 -8
View File
@@ -39,23 +39,30 @@ func (api *API) forceWorkspaceProxyHealthUpdate(ctx context.Context) {
// NOTE: this doesn't need a swagger definition since AGPL already has one, and
// this route overrides the AGPL one.
func (api *API) regions(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
//nolint:gocritic // this route intentionally requests resources that users
regions, err := api.fetchRegions(r.Context())
if err != nil {
httpapi.InternalServerError(rw, err)
return
}
httpapi.Write(r.Context(), rw, http.StatusOK, regions)
}
func (api *API) fetchRegions(ctx context.Context) (codersdk.RegionsResponse, error) {
//nolint:gocritic // this intentionally requests resources that users
// cannot usually access in order to give them a full list of available
// regions.
ctx = dbauthz.AsSystemRestricted(ctx)
primaryRegion, err := api.AGPL.PrimaryRegion(ctx)
if err != nil {
httpapi.InternalServerError(rw, err)
return
return codersdk.RegionsResponse{}, err
}
regions := []codersdk.Region{primaryRegion}
proxies, err := api.Database.GetWorkspaceProxies(ctx)
if err != nil {
httpapi.InternalServerError(rw, err)
return
return codersdk.RegionsResponse{}, err
}
// Only add additional regions if the proxy health is enabled.
@@ -81,9 +88,9 @@ func (api *API) regions(rw http.ResponseWriter, r *http.Request) {
}
}
httpapi.Write(ctx, rw, http.StatusOK, codersdk.RegionsResponse{
return codersdk.RegionsResponse{
Regions: regions,
})
}, nil
}
// @Summary Update workspace proxy
+1
View File
@@ -20,6 +20,7 @@
<meta property="entitlements" content="{{ .Entitlements }}" />
<meta property="appearance" content="{{ .Appearance }}" />
<meta property="experiments" content="{{ .Experiments }}" />
<meta property="regions" content="{{ .Regions }}" />
<!-- We need to set data-react-helmet to be able to override it in the workspace page -->
<link
rel="alternate icon"
+50 -17
View File
@@ -146,6 +146,7 @@ type Handler struct {
buildInfoJSON string
AppearanceFetcher func(ctx context.Context) (codersdk.AppearanceConfig, error)
RegionsFetcher func(ctx context.Context) (codersdk.RegionsResponse, error)
Entitlements atomic.Pointer[codersdk.Entitlements]
Experiments atomic.Pointer[codersdk.Experiments]
@@ -231,6 +232,7 @@ type htmlState struct {
Entitlements string
Appearance string
Experiments string
Regions string
}
type csrfState struct {
@@ -313,33 +315,64 @@ func (h *Handler) renderHTMLWithState(rw http.ResponseWriter, r *http.Request, f
})
err := eg.Wait()
if err == nil {
user, err := json.Marshal(db2sdk.User(user, orgIDs))
if err == nil {
state.User = html.EscapeString(string(user))
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
user, err := json.Marshal(db2sdk.User(user, orgIDs))
if err == nil {
state.User = html.EscapeString(string(user))
}
}()
entitlements := h.Entitlements.Load()
if entitlements != nil {
entitlements, err := json.Marshal(entitlements)
if err == nil {
state.Entitlements = html.EscapeString(string(entitlements))
}
wg.Add(1)
go func() {
defer wg.Done()
entitlements, err := json.Marshal(entitlements)
if err == nil {
state.Entitlements = html.EscapeString(string(entitlements))
}
}()
}
if h.AppearanceFetcher != nil {
cfg, err := h.AppearanceFetcher(ctx)
if err == nil {
appearance, err := json.Marshal(cfg)
wg.Add(1)
go func() {
defer wg.Done()
cfg, err := h.AppearanceFetcher(ctx)
if err == nil {
state.Appearance = html.EscapeString(string(appearance))
appearance, err := json.Marshal(cfg)
if err == nil {
state.Appearance = html.EscapeString(string(appearance))
}
}
}
}()
}
if h.RegionsFetcher != nil {
wg.Add(1)
go func() {
defer wg.Done()
regions, err := h.RegionsFetcher(ctx)
if err == nil {
regions, err := json.Marshal(regions)
if err == nil {
state.Regions = html.EscapeString(string(regions))
}
}
}()
}
experiments := h.Experiments.Load()
if experiments != nil {
experiments, err := json.Marshal(experiments)
if err == nil {
state.Experiments = html.EscapeString(string(experiments))
}
wg.Add(1)
go func() {
defer wg.Done()
experiments, err := json.Marshal(experiments)
if err == nil {
state.Experiments = html.EscapeString(string(experiments))
}
}()
}
wg.Wait()
}
}
+19
View File
@@ -92,6 +92,23 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
)
const queryKey = ["get-proxies"]
// This doesn't seem like an idiomatic way to get react-query to use the
// initial data without performing an API request on mount, but it works.
//
// If anyone would like to clean this up in the future, it should seed data
// from the `meta` tag if it exists, and not fetch the regions route.
const [initialData] = useState(() => {
// Build info is injected by the Coder server into the HTML document.
const regions = document.querySelector("meta[property=regions]")
if (regions) {
const rawContent = regions.getAttribute("content")
try {
return JSON.parse(rawContent as string)
} catch (ex) {
// Ignore this and fetch as normal!
}
}
})
const {
data: proxiesResp,
error: proxiesError,
@@ -100,6 +117,8 @@ export const ProxyProvider: FC<PropsWithChildren> = ({ children }) => {
} = useQuery({
queryKey,
queryFn: getWorkspaceProxies,
staleTime: initialData ? Infinity : undefined,
initialData,
})
// Every time we get a new proxiesResponse, update the latency check