blob: 3f86f013419db3ffcead397c7c83d0404a95c5c5 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'package:stream_channel/stream_channel.dart';
import '../error_code.dart' as error_code;
import 'exception.dart';
typedef ZeroArgumentFunction = Function();
/// A regular expression to match the exception prefix that some exceptions'
/// [Object.toString] values contain.
final _exceptionPrefix = RegExp(r'^([A-Z][a-zA-Z]*)?(Exception|Error): ');
/// Get a string description of an exception.
///
/// Many exceptions include the exception class name at the beginning of their
/// [toString], so we remove that if it exists.
String getErrorMessage(error) =>
error.toString().replaceFirst(_exceptionPrefix, '');
/// Like `try`/`finally`, run [body] and ensure that [whenComplete] runs
/// afterwards, regardless of whether [body] succeeded.
///
/// This is synchronicity-agnostic relative to [body]. If [body] returns a
/// [Future], this wil run asynchronously; otherwise it will run synchronously.
void tryFinally(Function() body, Function() whenComplete) {
var result;
try {
result = body();
} catch (_) {
whenComplete();
rethrow;
}
if (result is! Future) {
whenComplete();
return result;
} else {
return result.whenComplete(whenComplete);
}
}
/// A transformer that silently drops [FormatException]s.
final ignoreFormatExceptions = StreamTransformer<Object, Object>.fromHandlers(
handleError: (error, stackTrace, sink) {
if (error is FormatException) return;
sink.addError(error, stackTrace);
});
/// A transformer that sends error responses on [FormatException]s.
final StreamChannelTransformer<Object, Object> respondToFormatExceptions =
_RespondToFormatExceptionsTransformer();
class _RespondToFormatExceptionsTransformer
implements StreamChannelTransformer<Object, Object> {
@override
StreamChannel<Object> bind(StreamChannel<Object> channel) {
return channel.changeStream((stream) {
return stream.handleError((dynamic error) {
final formatException = error as FormatException;
var exception = RpcException(
error_code.PARSE_ERROR, 'Invalid JSON: ${formatException.message}');
channel.sink.add(exception.serialize(formatException.source));
}, test: (error) => error is FormatException);
});
}
}