# negotiate method

1. @override

Future <Result<NegotiatorState, NegotiatorError>> negotiate(

1. XMLNode nonza

)
override

Called with the currently received nonza `nonza` when the negotiator is active. If the negotiator is just elected to be the next one, then `nonza` is equal to the <stream:features /> nonza.

Returns the next state of the negotiator. If done or retryLater is selected, then negotiator won't be called again. If retryLater is returned, then the negotiator must switch some internal state to prevent getting matched immediately again. If ready is returned, then the negotiator indicates that it is not done with negotiation.

## Implementation

    @override
    Future<Result<NegotiatorState, NegotiatorError>> negotiate(
      XMLNode nonza,
    ) async {
      // negotiate is only called when we matched the stream feature, so we know
      // that the server advertises it.
      _supported = true;

      switch (_state) {
        case _StreamManagementNegotiatorState.ready:
          final sm =
              attributes.getManagerById<StreamManagementManager>(smManager)!;
          final srid = sm.state.streamResumptionId;
          final h = sm.state.s2c;

          // Attempt stream resumption first
          if (srid != null) {
            _log.finest(
              'Found stream resumption Id. Attempting to perform stream resumption',
            );
            _state = _StreamManagementNegotiatorState.resumeRequested;
            attributes.sendNonza(StreamManagementResumeNonza(srid, h));
          } else {
            _log.finest('Attempting to enable stream management');
            _state = _StreamManagementNegotiatorState.enableRequested;
            attributes.sendNonza(StreamManagementEnableNonza());
          }

          return const Result(NegotiatorState.ready);
        case _StreamManagementNegotiatorState.resumeRequested:
          if (nonza.tag == 'resumed') {
            _log.finest('Stream Management resumption successful');

            assert(
              resource.isNotEmpty,
              'Resume only works when we already have a resource bound and know about it',
            );

            // TODO(Unknown): Don't do this here. We trigger an event that the CSIManager
            //                can consume.
            final csi = attributes.getManagerById(csiManager) as CSIManager?;
            if (csi != null) {
              csi.restoreCSIState();
            }

            await _onStreamResumptionSuccessful(nonza);
            return const Result(NegotiatorState.skipRest);
          } else {
            // We assume it is <failed />
            _log.info(
              'Stream resumption failed. Expected <resumed />, got ${nonza.tag}, Proceeding with new stream...',
            );
            await _onStreamResumptionFailed();
            return const Result(NegotiatorState.retryLater);
          }
        case _StreamManagementNegotiatorState.enableRequested:
          if (nonza.tag == 'enabled') {
            _log.finest('Stream Management enabled');
            await _onStreamEnablementSuccessful(nonza);

            return const Result(NegotiatorState.done);
          } else {
            // We assume a <failed />
            _log.warning('Stream Management enablement failed');
            _onStreamEnablementFailed();
            return const Result(NegotiatorState.done);
          }
      }
    }