44
55import 'dart:async' ;
66import 'dart:html' ;
7+
78import 'package:_pub_shared/pubapi.dart' ;
89
910import '../_dom_helper.dart' ;
@@ -17,7 +18,7 @@ Future<R?> rpc<R>({
1718
1819 /// The async RPC call. If this throws, the error will be displayed as a modal
1920 /// popup, and then it will be re-thrown (or `onError` will be called).
20- Future <R ?> Function ()? fn,
21+ required Future <R ?> Function () fn,
2122
2223 /// Message to show when the RPC returns without exceptions.
2324 required Element ? successMessage,
@@ -37,12 +38,12 @@ Future<R?> rpc<R>({
3738 return null ;
3839 }
3940
40- // capture keys
41+ // Capture key down events.
4142 final keyDownSubscription = window.onKeyDown.listen ((event) {
4243 event.preventDefault ();
4344 event.stopPropagation ();
4445 });
45- // disable inputs and buttons that are not already disabled
46+ // Disable inputs and buttons that are not already disabled.
4647 final inputs = document
4748 .querySelectorAll ('input' )
4849 .cast <InputElement >()
@@ -67,22 +68,21 @@ Future<R?> rpc<R>({
6768 }
6869
6970 R ? result;
70- Exception ? error;
71- String ? errorMessage;
71+ ({Exception exception, String message})? error;
7272 try {
73- result = await fn ! ();
73+ result = await fn ();
7474 } on RequestException catch (e) {
7575 final asJson = e.bodyAsJson ();
7676 if (e.status == 401 && asJson.containsKey ('go' )) {
77- final location = e. bodyAsJson () ['go' ] as String ;
77+ final location = asJson ['go' ] as String ;
7878 final locationUri = Uri .tryParse (location);
7979 if (locationUri != null && locationUri.toString ().isNotEmpty) {
8080 await cancelSpinner ();
81- final errorObject = e. bodyAsJson () ['error' ] as Map ? ;
81+ final errorObject = asJson ['error' ] as Map ? ;
8282 final message = errorObject? ['message' ];
8383 await modalMessage (
8484 'Further consent needed.' ,
85- Element . p ()
85+ ParagraphElement ()
8686 ..text = [
8787 if (message != null ) message,
8888 'You will be redirected, please authorize the action.' ,
@@ -101,21 +101,25 @@ Future<R?> rpc<R>({
101101 return null ;
102102 }
103103 }
104- error = e;
105- errorMessage = _requestExceptionMessage (e) ?? 'Unexpected error: $e ' ;
104+ error = (
105+ exception: e,
106+ message: _requestExceptionMessage (asJson) ?? 'Unexpected error: $e '
107+ );
106108 } catch (e) {
107- error = Exception ('Unexpected error: $e ' );
108- errorMessage = 'Unexpected error: $e ' ;
109+ error = (
110+ exception: Exception ('Unexpected error: $e ' ),
111+ message: 'Unexpected error: $e '
112+ );
109113 } finally {
110114 await cancelSpinner ();
111115 }
112116
113117 if (error != null ) {
114- await modalMessage ('Error' , await markdown (errorMessage ! ));
118+ await modalMessage ('Error' , await markdown (error.message ));
115119 if (onError != null ) {
116- return await onError (error);
120+ return await onError (error.exception );
117121 } else {
118- throw error;
122+ throw error.exception ;
119123 }
120124 }
121125
@@ -128,37 +132,18 @@ Future<R?> rpc<R>({
128132 return result;
129133}
130134
131- String ? _requestExceptionMessage (RequestException e) {
132- try {
133- final map = e.bodyAsJson ();
134- String ? message;
135-
136- if (map['error' ] is Map ) {
137- final errorMap = map['error' ] as Map ;
138- if (errorMap['message' ] is String ) {
139- message = errorMap['message' ] as String ;
140- }
141- }
142-
143- // TODO: remove after the server is migrated to returns only `{'error': {'message': 'XX'}}`
144- if (message == null && map['message' ] is String ) {
145- message = map['message' ] as String ;
146- }
147-
148- // TODO: check if we ever send responses like this and remove if not
149- if (message == null && map['error' ] is String ) {
150- message = map['error' ] as String ;
151- }
152-
153- return message;
154- } on FormatException catch (_) {
155- // ignore bad body
156- }
157- return null ;
158- }
159-
160- Element _createSpinner () => Element .div ()
135+ String ? _requestExceptionMessage (Map <String , Object ?> jsonBody) =>
136+ switch (jsonBody) {
137+ {'error' : {'message' : final String errorMessage}} => errorMessage,
138+ // TODO: Remove after the server is migrated to return only `{'error': {'message': 'XX'}}`.
139+ {'message' : final String errorMessage} => errorMessage,
140+ // TODO: Check if we ever send responses like this and remove if not.
141+ {'error' : final String errorMessage} => errorMessage,
142+ _ => null ,
143+ };
144+
145+ Element _createSpinner () => DivElement ()
161146 ..className = 'spinner-frame'
162147 ..children = [
163- Element . div ()..className = 'spinner' ,
148+ DivElement ()..className = 'spinner' ,
164149 ];
0 commit comments