Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perform one request to get all versions #1006

Merged
merged 1 commit into from
Dec 1, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/frontend/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -82,6 +82,7 @@ module.exports = {
'reducers/output/meta.ts',
'reducers/output/mir.ts',
'reducers/output/wasm.ts',
'reducers/versions.ts',
'reducers/websocket.ts',
'websocketActions.ts',
'websocketMiddleware.ts',
1 change: 1 addition & 0 deletions ui/frontend/.prettierignore
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ node_modules
!reducers/output/meta.ts
!reducers/output/mir.ts
!reducers/output/wasm.ts
!reducers/versions.ts
!reducers/websocket.ts
!websocketActions.ts
!websocketMiddleware.ts
50 changes: 1 addition & 49 deletions ui/frontend/actions.ts
Original file line number Diff line number Diff line change
@@ -27,7 +27,6 @@ import {
ProcessAssembly,
Position,
makePosition,
Version,
Crate,
} from './types';

@@ -48,14 +47,7 @@ export const routes = {
macroExpansion: '/macro-expansion',
meta: {
crates: '/meta/crates',
version: {
stable: '/meta/version/stable',
beta: '/meta/version/beta',
nightly: '/meta/version/nightly',
rustfmt: '/meta/version/rustfmt',
clippy: '/meta/version/clippy',
miri: '/meta/version/miri',
},
versions: '/meta/versions',
gistSave: '/meta/gist',
gistLoad: '/meta/gist/id',
},
@@ -103,8 +95,6 @@ export enum ActionType {
MacroExpansionFailed = 'MACRO_EXPANSION_FAILED',
RequestCratesLoad = 'REQUEST_CRATES_LOAD',
CratesLoadSucceeded = 'CRATES_LOAD_SUCCEEDED',
RequestVersionsLoad = 'REQUEST_VERSIONS_LOAD',
VersionsLoadSucceeded = 'VERSIONS_LOAD_SUCCEEDED',
NotificationSeen = 'NOTIFICATION_SEEN',
BrowserWidthChanged = 'BROWSER_WIDTH_CHANGED',
}
@@ -488,42 +478,6 @@ export function performCratesLoad(): ThunkAction {
};
}

const requestVersionsLoad = () =>
createAction(ActionType.RequestVersionsLoad);

const receiveVersionsLoadSuccess = ({
stable, beta, nightly, rustfmt, clippy, miri,
}: {
stable: Version, beta: Version, nightly: Version, rustfmt: Version, clippy: Version, miri: Version,
}) =>
createAction(ActionType.VersionsLoadSucceeded, { stable, beta, nightly, rustfmt, clippy, miri });

export function performVersionsLoad(): ThunkAction {
return function(dispatch) {
dispatch(requestVersionsLoad());

const stable = jsonGet(routes.meta.version.stable);
const beta = jsonGet(routes.meta.version.beta);
const nightly = jsonGet(routes.meta.version.nightly);
const rustfmt = jsonGet(routes.meta.version.rustfmt);
const clippy = jsonGet(routes.meta.version.clippy);
const miri = jsonGet(routes.meta.version.miri);

const all = Promise.all([stable, beta, nightly, rustfmt, clippy, miri]);

return all
.then(([stable, beta, nightly, rustfmt, clippy, miri]) => dispatch(receiveVersionsLoadSuccess({
stable,
beta,
nightly,
rustfmt,
clippy,
miri,
})));
// TODO: Failure case
};
}

const notificationSeen = (notification: Notification) =>
createAction(ActionType.NotificationSeen, { notification });

@@ -654,8 +608,6 @@ export type Action =
| ReturnType<typeof receiveMacroExpansionFailure>
| ReturnType<typeof requestCratesLoad>
| ReturnType<typeof receiveCratesLoadSuccess>
| ReturnType<typeof requestVersionsLoad>
| ReturnType<typeof receiveVersionsLoadSuccess>
| ReturnType<typeof notificationSeen>
| ReturnType<typeof browserWidthChanged>
| ReturnType<typeof wsExecuteRequest>
2 changes: 1 addition & 1 deletion ui/frontend/index.tsx
Original file line number Diff line number Diff line change
@@ -15,7 +15,6 @@ import {
selectText,
addImport,
performCratesLoad,
performVersionsLoad,
reExecuteWithBacktrace,
browserWidthChanged,
} from './actions';
@@ -27,6 +26,7 @@ import { featureFlagsForceDisableAll, featureFlagsForceEnableAll } from './reduc
import { disableSyncChangesToStorage } from './reducers/globalConfiguration';
import Router from './Router';
import configureStore from './configureStore';
import { performVersionsLoad } from './reducers/versions';

const store = configureStore(window);

62 changes: 37 additions & 25 deletions ui/frontend/reducers/versions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,37 @@
import { Action, ActionType } from '../actions';
import { Version } from '../types';

const DEFAULT: State = {
};

export interface State {
stable?: Version;
beta?: Version;
nightly?: Version;
rustfmt?: Version;
clippy?: Version;
miri?: Version;
}

export default function crates(state = DEFAULT, action: Action) {
switch (action.type) {
case ActionType.VersionsLoadSucceeded: {
const { stable, beta, nightly, rustfmt, clippy, miri } = action;
return { stable, beta, nightly, rustfmt, clippy, miri };
}
default:
return state;
}
}
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import * as z from 'zod';

import { adaptFetchError, jsonGet, routes } from '../actions';
import { ChannelVersion } from '../types';

const sliceName = 'versions';

const initialState: State = {};

type State = Partial<Response>;

const Response = z.object({
stable: ChannelVersion,
beta: ChannelVersion,
nightly: ChannelVersion,
});

type Response = z.infer<typeof Response>;

export const performVersionsLoad = createAsyncThunk(sliceName, async () => {
const d = await adaptFetchError(() => jsonGet(routes.meta.versions));
return Response.parseAsync(d);
});

const slice = createSlice({
name: sliceName,
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(performVersionsLoad.fulfilled, (state, versions) => {
Object.assign(state, versions.payload);
});
},
});

export default slice.reducer;
12 changes: 6 additions & 6 deletions ui/frontend/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -99,12 +99,12 @@ const LABELS: { [index in PrimaryActionCore]: string } = {

export const getExecutionLabel = createSelector(primaryActionSelector, primaryAction => LABELS[primaryAction]);

const getStable = (state: State) => state.versions?.stable;
const getBeta = (state: State) => state.versions?.beta;
const getNightly = (state: State) => state.versions?.nightly;
const getRustfmt = (state: State) => state.versions?.rustfmt;
const getClippy = (state: State) => state.versions?.clippy;
const getMiri = (state: State) => state.versions?.miri;
const getStable = (state: State) => state.versions.stable?.rustc;
const getBeta = (state: State) => state.versions.beta?.rustc;
const getNightly = (state: State) => state.versions.nightly?.rustc;
const getRustfmt = (state: State) => state.versions.nightly?.rustfmt;
const getClippy = (state: State) => state.versions.nightly?.clippy;
const getMiri = (state: State) => state.versions?.nightly?.miri;

const versionNumber = (v: Version | undefined) => v ? v.version : '';
export const stableVersionText = createSelector(getStable, versionNumber);
23 changes: 18 additions & 5 deletions ui/frontend/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as z from 'zod';

export type Page = 'index' | 'help';

export interface Position {
@@ -19,11 +21,22 @@ export interface Crate {
version: string;
}

export interface Version {
version: string;
hash: string;
date: string;
}
export const Version = z.object({
version: z.string(),
hash: z.string(),
date: z.string(),
});

export type Version = z.infer<typeof Version>;

export const ChannelVersion = z.object({
rustc: Version,
rustfmt: Version,
clippy: Version,
miri: Version.optional(),
});

export type ChannelVersion = z.infer<typeof ChannelVersion>;

export interface CommonEditorProps {
code: string;
16 changes: 16 additions & 0 deletions ui/src/main.rs
Original file line number Diff line number Diff line change
@@ -429,6 +429,22 @@ struct MetaCratesResponse {
crates: Arc<[CrateInformation]>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
struct MetaVersionsResponse {
stable: MetaChannelVersionResponse,
beta: MetaChannelVersionResponse,
nightly: MetaChannelVersionResponse,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
struct MetaChannelVersionResponse {
rustc: MetaVersionResponse,
rustfmt: MetaVersionResponse,
clippy: MetaVersionResponse,
#[serde(skip_serializing_if = "Option::is_none")]
miri: Option<MetaVersionResponse>,
}

#[derive(Debug, Clone, PartialEq, Serialize)]
struct MetaVersionResponse {
version: Arc<str>,
1 change: 1 addition & 0 deletions ui/src/metrics.rs
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@ pub(crate) enum Endpoint {
Clippy,
MacroExpansion,
MetaCrates,
MetaVersions,
MetaVersionStable,
MetaVersionBeta,
MetaVersionNightly,
73 changes: 63 additions & 10 deletions ui/src/server_axum.rs
Original file line number Diff line number Diff line change
@@ -10,8 +10,8 @@ use crate::{
ExecuteRequest, ExecuteResponse, ExecuteSnafu, FormatRequest, FormatResponse, FormatSnafu,
GhToken, GistCreationSnafu, GistLoadingSnafu, MacroExpansionRequest, MacroExpansionResponse,
MacroExpansionSnafu, MetaCratesResponse, MetaGistCreateRequest, MetaGistResponse,
MetaVersionResponse, MetricsToken, MiriRequest, MiriResponse, MiriSnafu, MiriVersionSnafu,
Result, ShutdownCoordinatorSnafu, TimeoutSnafu, VersionsSnafu,
MetaVersionResponse, MetaVersionsResponse, MetricsToken, MiriRequest, MiriResponse, MiriSnafu,
MiriVersionSnafu, Result, ShutdownCoordinatorSnafu, TimeoutSnafu, VersionsSnafu,
};
use async_trait::async_trait;
use axum::{
@@ -76,6 +76,7 @@ pub(crate) async fn serve(config: Config) {
.route("/miri", post(miri))
.route("/macro-expansion", post(macro_expansion))
.route("/meta/crates", get_or_post(meta_crates))
.route("/meta/versions", get(meta_versions))
.route("/meta/version/stable", get_or_post(meta_version_stable))
.route("/meta/version/beta", get_or_post(meta_version_beta))
.route("/meta/version/nightly", get_or_post(meta_version_nightly))
@@ -351,6 +352,14 @@ async fn meta_crates(
apply_timestamped_caching(value, if_none_match)
}

async fn meta_versions(
Extension(cache): Extension<Arc<SandboxCache>>,
if_none_match: Option<TypedHeader<IfNoneMatch>>,
) -> Result<impl IntoResponse> {
let value = track_metric_no_request_async(Endpoint::MetaVersions, || cache.versions()).await?;
apply_timestamped_caching(value, if_none_match)
}

async fn meta_version_stable(
Extension(cache): Extension<Arc<SandboxCache>>,
if_none_match: Option<TypedHeader<IfNoneMatch>>,
@@ -555,7 +564,8 @@ type Stamped<T> = (T, SystemTime);
#[derive(Debug, Default)]
struct SandboxCache {
crates: CacheOne<MetaCratesResponse>,
versions: CacheOne<Arc<Versions>>,
versions: CacheOne<MetaVersionsResponse>,
raw_versions: CacheOne<Arc<Versions>>,
}

impl SandboxCache {
@@ -566,10 +576,18 @@ impl SandboxCache {
.await
}

async fn versions(&self) -> Result<Stamped<Arc<Versions>>> {
async fn versions(&self) -> Result<Stamped<MetaVersionsResponse>> {
let coordinator = Coordinator::new_docker().await;

self.versions
.fetch(|| async { Ok(coordinator.versions().await.context(VersionsSnafu)?.into()) })
.await
}

async fn raw_versions(&self) -> Result<Stamped<Arc<Versions>>> {
let coordinator = Coordinator::new_docker().await;

self.raw_versions
.fetch(|| async {
Ok(Arc::new(
coordinator.versions().await.context(VersionsSnafu)?,
@@ -579,37 +597,37 @@ impl SandboxCache {
}

async fn version_stable(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = (&v.stable.rustc).into();
Ok((v, t))
}

async fn version_beta(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = (&v.beta.rustc).into();
Ok((v, t))
}

async fn version_nightly(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = (&v.nightly.rustc).into();
Ok((v, t))
}

async fn version_rustfmt(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = (&v.nightly.rustfmt).into();
Ok((v, t))
}

async fn version_clippy(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = (&v.nightly.clippy).into();
Ok((v, t))
}

async fn version_miri(&self) -> Result<Stamped<MetaVersionResponse>> {
let (v, t) = self.versions().await?;
let (v, t) = self.raw_versions().await?;
let v = v.nightly.miri.as_ref().context(MiriVersionSnafu)?;
let v = v.into();
Ok((v, t))
@@ -769,6 +787,41 @@ pub(crate) mod api_orchestrator_integration_impls {
}
}

impl From<Versions> for crate::MetaVersionsResponse {
fn from(other: Versions) -> Self {
let Versions {
stable,
beta,
nightly,
} = other;
let [stable, beta, nightly] = [stable, beta, nightly].map(Into::into);
Self {
stable,
beta,
nightly,
}
}
}

impl From<ChannelVersions> for crate::MetaChannelVersionResponse {
fn from(other: ChannelVersions) -> Self {
let ChannelVersions {
rustc,
rustfmt,
clippy,
miri,
} = other;
let [rustc, rustfmt, clippy] = [rustc, rustfmt, clippy].map(|v| (&v).into());
let miri = miri.map(|v| (&v).into());
Self {
rustc,
rustfmt,
clippy,
miri,
}
}
}

impl From<&Version> for crate::MetaVersionResponse {
fn from(other: &Version) -> Self {
Self {