4343import com .microsoft .intellij .helpers .UIHelperImpl ;
4444import com .microsoft .intellij .serviceexplorer .azure .SignInOutAction ;
4545import com .microsoft .intellij .ui .DeviceLoginUI ;
46+ import com .microsoft .intellij .ui .ErrorWindow ;
4647import com .microsoft .intellij .ui .ServicePrincipalLoginDialog ;
4748import com .microsoft .intellij .ui .SignInWindow ;
4849import com .microsoft .intellij .util .AzureLoginHelper ;
4950import com .microsoft .tooling .msservices .components .DefaultLoader ;
5051import com .microsoft .tooling .msservices .serviceexplorer .AzureIconSymbol ;
52+ import lombok .Lombok ;
5153import org .apache .commons .collections4 .CollectionUtils ;
5254import org .apache .commons .lang3 .StringUtils ;
5355import org .jetbrains .annotations .NotNull ;
6466import java .util .Map ;
6567import java .util .Optional ;
6668import java .util .concurrent .Callable ;
69+ import java .util .concurrent .CancellationException ;
70+ import java .util .concurrent .CompletableFuture ;
71+ import java .util .function .Supplier ;
6772
6873import static com .microsoft .azuretools .telemetry .TelemetryConstants .ACCOUNT ;
6974import static com .microsoft .azuretools .telemetry .TelemetryConstants .AZURE_ENVIRONMENT ;
@@ -76,6 +81,7 @@ public class AzureSignInAction extends AzureAnAction {
7681 private static final Logger LOGGER = Logger .getInstance (AzureSignInAction .class );
7782 private static final String SIGN_IN = "Azure Sign In..." ;
7883 private static final String SIGN_OUT = "Azure Sign Out..." ;
84+ private static final String SIGN_IN_ERROR = "Sign In Error" ;
7985
8086 public AzureSignInAction () {
8187 super (AuthMethodManager .getInstance ().isSignedIn () ? SIGN_OUT : SIGN_IN );
@@ -241,11 +247,22 @@ private static Mono<Boolean> signInIfNotSignedInInternal(Project project) {
241247 if (auth .getType () != AuthType .DEVICE_CODE ) {
242248 single = loginNonDeviceCodeSingle (auth );
243249 } else {
244-
245250 single = loginDeviceCodeSingle ().map (account -> {
246251 AzureTaskManager .getInstance ().runLater (() -> deviceLoginUI .promptDeviceCode (account .getDeviceCode ()));
247- return account .continueLogin ().map (ac -> fromAccountEntity (ac .getEntity ())).doFinally (signal ->
248- deviceLoginUI .closePrompt ()).subscribeOn (Schedulers .boundedElastic ()).block ();
252+
253+ CompletableFuture <AuthMethodDetails > future =
254+ account .continueLogin ().map (ac -> fromAccountEntity (ac .getEntity ())).doFinally (signal -> deviceLoginUI .closePrompt ()).toFuture ();
255+ deviceLoginUI .setFuture (future );
256+
257+ try {
258+ return future .get ();
259+ } catch (Throwable ex ) {
260+ if (!(ex instanceof CancellationException )) {
261+ ex .printStackTrace ();
262+ ErrorWindow .show (project , ex .getMessage (), SIGN_IN_ERROR );
263+ }
264+ return new AuthMethodDetails ();
265+ }
249266 });
250267 }
251268
@@ -275,7 +292,9 @@ private static Single<DeviceCodeAccount> loginDeviceCodeSingle() {
275292 final ProgressIndicator indicator = ProgressManager .getInstance ().getProgressIndicator ();
276293 indicator .setIndeterminate (true );
277294 final AzureAccount az = Azure .az (AzureAccount .class );
278- return (DeviceCodeAccount ) az .loginAsync (AuthType .DEVICE_CODE , true ).block ();
295+ return (DeviceCodeAccount ) checkCanceled (indicator , az .loginAsync (AuthType .DEVICE_CODE , true ), () -> {
296+ throw Lombok .sneakyThrow (new InterruptedException ("user cancel" ));
297+ });
279298 });
280299 return AzureTaskManager .getInstance ().runInBackgroundAsObservable (deviceCodeTask ).toSingle ();
281300 }
@@ -295,13 +314,16 @@ private static AuthMethodDetails doLogin(ProgressIndicator indicator, AuthConfig
295314 AuthMethodDetails authMethodDetailsResult = new AuthMethodDetails ();
296315 switch (auth .getType ()) {
297316 case SERVICE_PRINCIPAL :
298- authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInServicePrincipal (auth )), "sp" );
317+ authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInServicePrincipal (auth ),
318+ AuthMethodDetails ::new ), "sp" );
299319 break ;
300320 case AZURE_CLI :
301- authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInAzureCli ()), "az" );
321+ authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInAzureCli (),
322+ AuthMethodDetails ::new ), "az" );
302323 break ;
303324 case OAUTH2 :
304- authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInOAuth ()), "oauth" );
325+ authMethodDetailsResult = call (() -> checkCanceled (indicator , IdentityAzureManager .getInstance ().signInOAuth (),
326+ AuthMethodDetails ::new ), "oauth" );
305327 break ;
306328 default :
307329 break ;
@@ -328,9 +350,9 @@ private static <T> T call(Callable<T> loginCallable, String authMethod) {
328350 }
329351 }
330352
331- private static AuthMethodDetails checkCanceled (ProgressIndicator indicator , Mono <? extends AuthMethodDetails > mono ) {
332- final Mono <AuthMethodDetails > cancelMono = Flux .interval (Duration .ofSeconds (1 )).map (ignore -> indicator .isCanceled ())
333- .any (cancel -> cancel ).map (ignore -> new AuthMethodDetails ()).subscribeOn (Schedulers .boundedElastic ());
353+ private static < T > T checkCanceled (ProgressIndicator indicator , Mono <? extends T > mono , Supplier < T > supplier ) {
354+ final Mono <T > cancelMono = Flux .interval (Duration .ofSeconds (1 )).map (ignore -> indicator .isCanceled ())
355+ .any (cancel -> cancel ).map (ignore -> supplier . get ()).subscribeOn (Schedulers .boundedElastic ());
334356 return Mono .firstWithSignal (cancelMono , mono .subscribeOn (Schedulers .boundedElastic ())).block ();
335357 }
336358
0 commit comments