authenticate method

  1. @override
Future<WebSocketCommunicator?> authenticate({
  1. required Stream<DeviceCommand> commandStream,
  2. required WebSocket socket,
})
override

Authenticates the current communicator. The Future will resolve with a valid WebSocketCommunicator if the authentication is successful and null otherwise.

Implementation

@override
Future<WebSocketCommunicator?> authenticate({
  required Stream<DeviceCommand> commandStream,
  required WebSocket socket,
}) async {
  final state = AuthenticationState(
    commandStream: commandStream,
    socket: socket,
  );

  Completer? completer = Completer<void>();
  final future = completer.future;

  final timer = Timer(const Duration(minutes: 2), () async {
    try {
      logger.info(
        '[CONNECTION]: connection timed out.',
      );

      completer?.completeError('[CONNECTION]: connection timed out.');
      completer = null;
    } catch (e) {
      // no-op
    }
  });

  final sub = commandStream.listen((cmd) async {
    if (_handlers.containsKey(cmd.type)) {
      final handler = _handlers[cmd.type];
      await handler!.handle(
        command: cmd,
        state: state,
      );
      if (state.success != null) {
        completer?.complete();
        completer = null;
      }
    } else {
      logger.info(
        '[CLOSE]: unknown command type: [${cmd.type}], ignoring...',
      );
      completer?.complete(null);
      completer = null;
    }
  }, onError: (Object e, StackTrace stack) {
    logger.severe('[SOCKET]: error listening to socket', e, stack);
    completer?.completeError('[SOCKET]: error listening to socket');
    completer = null;
  });

  try {
    await future;
  } catch (e, stack) {
    logger.severe('Error in authenticator', e, stack);
  }
  timer.cancel();

  await sub.cancel();

  if (state.success == true) {
    state.communicator!.attachSocket(socket);
  }

  return state.success == true ? state.communicator : null;
}