init method

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

Implementation

Future<void> init({bool verbose = false}) async {
  final trustedProxies = TrustedProxies(configManager.trustedProxies);
  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 = TrustedProxySocketServer(
    bindAddress,
    configManager.port,
    trustedProxies: trustedProxies,
    overrideStatusCode: false,
    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();

  for (final module in <ConsoleModule>[
    ServerModule(this),
    WorldModule(this),
    ModerationModule(this),
    RolesModule(this),
    ContentModule(this),
  ]) {
    await consoler.install(module);
  }
  await loadWorlds();
  _uptime.start();
}