send method

  1. @override
Future<void> send(
  1. RpcTransportMessage message
)
override

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);
}