serve method

Future<Server> serve(
  1. Object address,
  2. int port, {
  3. SecurityContextFactory? securityContextFactory,
  4. int backlog = 0,
  5. bool v6Only = false,
  6. bool requestClientCertificate = false,
  7. bool shared = false,
  8. int isolates = 1,
  9. LoggerFactory? loggerFactory = defaultLoggerFactory,
  10. bool showBanner = true,
  11. bool showUrl = true,
})

Starts a Server that listens on the specified address and port and sends requests to mounted Handler created by HandlerFactory.

The address can either be a String or an InternetAddress. If address is a String, ApplicationServer.bind will perform a InternetAddress.lookup and use the first value in the list. To listen on the loopback adapter, which will allow only incoming connections from the local host, use the value InternetAddress.loopbackIPv4 or InternetAddress.loopbackIPv6. To allow for incoming connection from the network use either one of the values InternetAddress.anyIPv4 or InternetAddress.anyIPv6 to bind to all interfaces or the IP address of a specific interface.

If port has the value 0, an ephemeral port will be chosen by the system.

Incoming client connections are promoted to secure connections, using the certificate and key set in SecurityContext created by securityContextFactory.

The optional argument backlog can be used to specify the listen backlog for the underlying OS listen setup. If backlog has the value of 0 (the default) a reasonable value will be chosen by the system.

If requestClientCertificate is true, the server will request clients to authenticate with a client certificate. The server will advertise the names of trusted issuers of client certificates, getting them from a SecurityContext, where they have been set using SecurityContext.setClientAuthorities.

The optional argument shared specifies whether additional Server objects can bind to the same combination of address, port and v6Only. If shared is true and more Servers from this isolate or other isolates are bound to the port, then the incoming connections will be distributed among all the bound Servers. Connections can be distributed over multiple isolates this way.

The optional argument loggerFactory specifies a logger factory that creates a Logger for this Server instance.

Implementation

// TODO(serve): document isolates argument.
Future<Server> serve(
  Object address,
  int port, {
  SecurityContextFactory? securityContextFactory,
  int backlog = 0,
  bool v6Only = false,
  bool requestClientCertificate = false,
  bool shared = false,
  int isolates = 1,
  LoggerFactory? loggerFactory = defaultLoggerFactory,
  bool showBanner = true,
  bool showUrl = true,
}) async {
  if (isolates < 0) {
    // TODO(serve): add error message.
    throw ArgumentError.value(isolates, 'isolates');
  } else if (isolates == 0) {
    isolates = min(1, Platform.numberOfProcessors - 1);
  }

  shared = shared || isolates > 1;

  Future<Server> create(SendPort? sendPort) async {
    var handlerFactory = await this;
    var handler = await handlerFactory();

    SecurityContext? securityContext;

    if (securityContextFactory != null) {
      securityContext = await securityContextFactory();
    }

    Logger? logger;

    if (loggerFactory != null) {
      logger = await loggerFactory();
    }

    if (sendPort == null) {
      return await Server.bind(handler, address, port,
          securityContext: securityContext,
          backlog: backlog,
          v6Only: v6Only,
          requestClientCertificate: requestClientCertificate,
          shared: shared,
          logger: logger);
    } else {
      return await IsolateServer.bind(sendPort, handler, address, port,
          securityContext: securityContext,
          backlog: backlog,
          v6Only: v6Only,
          requestClientCertificate: requestClientCertificate,
          shared: shared,
          logger: logger);
    }
  }

  if (securityContextFactory != null) {
    // check if securityContextFactory is error safe, not guaranteed.
    await securityContextFactory();
  }

  Logger? logger;

  if (loggerFactory != null) {
    // check if loggerFactory is error safe, not guaranteed.
    logger = await loggerFactory();
  }

  var url = getUrl(address, port, securityContextFactory != null);

  if (showBanner && logger != null) {
    logBanner(logger);
  }

  if (showUrl && logger != null) {
    logUrl(logger, url);
  }

  Server server;

  if (isolates == 1) {
    server = await create(null);
  } else {
    server = await MultiIsolateServer.spawn(isolates, create, //
        url: url,
        logger: logger);
  }

  registerExtensions(server);
  return server;
}