init method

Future<void> init({
  1. bool verbose = false,
})

Implementation

Future<void> init({bool verbose = false}) async {
  if (verbose) {
    consoler.minLogLevel = LogLevel.verbose;
  }
  log(
    "Starting server on ${configManager.host}:${configManager.port}",
    level: LogLevel.info,
  );
  log('Verbose logging activated', level: LogLevel.verbose);
  try {
    await initPluginSystem(
      externalLibrary: await loadExternalPluginLibrary(),
    );
    log('Plugin system initialized', level: LogLevel.info);
  } catch (e) {
    log(
      'Error initializing plugin system: $e, continuing without',
      level: LogLevel.warning,
    );
  }
  final bindAddress = await _resolveBindAddress(configManager.host);
  SecurityContext? securityContext;
  try {
    final privateKey = await File(p.join(rootDirectory, 'certs/server.key'))
        .readAsBytes();
    final certificate = await File(p.join(rootDirectory, 'certs/server.crt'))
        .readAsBytes();
    securityContext = SecurityContext()
      ..usePrivateKeyBytes(privateKey)
      ..useCertificateChainBytes(certificate);
    log('Certificates found, using secure connection', level: LogLevel.info);
  } on PathNotFoundException catch (_) {
    log(
      bindAddress.isLoopback
          ? 'No certificates found; using a local-only connection.'
          : 'No certificates found; the listener itself is not encrypted.',
      level: bindAddress.isLoopback ? LogLevel.info : LogLevel.warning,
    );
  }
  if (configManager.whitelistEnabled && !configManager.accountRequired) {
    log(
      'Whitelist is enabled, but account requirement is disabled. With no accounts, the whitelist has no effect.',
      level: LogLevel.warning,
    );
  }
  final authenticationChallenges = challengeManager;
  if (authenticationChallenges != null) {
    final origin = resolveAuthenticationOrigin(
      publicAddress: configManager.publicAddress,
      host: configManager.host,
      port: configManager.port,
      tlsEnabled: securityContext != null,
    );
    authenticationChallenges.serverId = origin;
    if (securityContext == null && origin.startsWith('wss://')) {
      log(
        'Using the public WSS origin $origin. TLS must terminate at a '
        'trusted reverse proxy in front of this server.',
        level: LogLevel.info,
      );
    } else if (securityContext == null && bindAddress.isLoopback) {
      log(
        'Authentication is restricted to the local machine without TLS.',
        level: LogLevel.info,
      );
    } else if (securityContext == null) {
      throw StateError(
        'Account authentication requires TLS outside the local machine. '
        'Install certs/server.crt and certs/server.key, configure '
        'publicAddress with a WSS URL for a reverse proxy.',
      );
    }
  }
  final server = _server = NetworkerSocketServer(
    bindAddress,
    configManager.port,
    securityContext: securityContext,
    filterConnections: buildFilterConnections(
      loadProperty: (request) async =>
          (getWorld(request.uri.path) ?? defaultWorld).eventSystem.runPing(
            request,
            GameProperty.defaultProperty.copyWith(
              description: configManager.description,
              hasThumbnail: await hasThumbnail(),
              maxPlayers: configManager.maxPlayers,
              currentPlayers: _server?.clientConnections.length,
              packsSignature: assetManager.createSignature(),
              protocolVersions: kSetonixServerProtocolVersions,
              protocolCapabilities: kSetonixProtocolCapabilities,
            ),
          ),
      loadThumbnail: (_) => loadThumbnail(),
    ),
  );

  final transformer = _pipe = NetworkerPipeTransformer<String, WorldEvent>(
    WorldEventMapper.fromJson,
    (e) => e.toJson(),
  );
  transformer.read.listen(_onClientEvent);
  server
    ..clientConnect.listen(_onJoin)
    ..clientDisconnect.listen(_onLeave)
    ..connect(
      FilteredNetworkerPipe<Uint8List>(
        filterDecoded: (data, _) => data.length <= kMaxNetworkEventBytes,
      )..connect(StringNetworkerPlugin()..connect(transformer)),
    );
  await _server?.init();

  consoler.registerPrograms({
    'stop': StopProgram(this),
    'save': SaveProgram(this),
    'packs': PacksProgram(this),
    'players': PlayersProgram(this),
    'say': SayProgram(this),
    'reset': ResetProgram(this),
    'role': RoleProgram(this),
    'roles': RolesProgram(this),
    'kick': KickProgram(this),
    'ban': BanProgram(this, banned: true),
    'unban': BanProgram(this, banned: false),
    'bans': BansProgram(this),
    'whitelist': WhitelistProgram(this),
    'worlds': WorldsProgram(this),
    'modes': ModesProgram(this),
    'name': NameProgram(this),
    'scripts': ScriptsProgram(this),
    null: UnknownProgram(),
  });
  await loadWorlds();
}