send method
Send a message to the remote side.
A send on a CLOSED channel returns normally and delivers nothing. Both
shipped implementations do this -- if (_closed) return -- so it is the
convention rather than one channel's quirk, and it means the future
completing is not evidence the peer received anything. Measured on the direct
channel after the peer closed: the send returned normally / the peer received [] / our isClosed true.
Callers that need to know go through RpcChannelTransport, which throws
RpcClosedException from its own sendMessage instead. A channel used
directly has only isClosed to check.
Implementation
@override
Future<void> send(RpcTransportMessage message) async {
if (_closed) return;
Uint8List frame;
if (message.payload != null) {
frame = RpcChannelFrame.encodeData(
streamId: message.streamId,
payload: message.payload!,
endOfStream: message.isEndOfStream,
);
} else if (message.metadata != null) {
frame = RpcChannelFrame.encodeMetadata(
streamId: message.streamId,
metadata: message.metadata!,
endOfStream: message.isEndOfStream,
);
// The policy counts header text; the peer bounds this encoded frame by
// the same number, and a server closes the connection over it.
final encoded = frame.length - RpcChannelFrame.headerSize;
if (_refuses(RpcChannelFrame.flagMetadata, encoded)) {
throw RpcMetadataViolationException(
'Metadata too large once encoded: $encoded bytes > '
'${_policy.maxMetadataBytes}',
name: 'metadata',
);
}
} else if (message.isEndOfStream) {
frame = RpcChannelFrame.encodeEndOfStream(message.streamId);
} else {
return;
}
final held = _held;
if (held != null) {
held.add(frame);
return _released.future;
}
await _channel.send(frame);
}