// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

library http_multi_server;

import 'dart:async';
import 'dart:io';

import 'src/multi_headers.dart';
import 'src/utils.dart';

/// The error code for an error caused by a port already being in use.
final _addressInUseErrno = _computeAddressInUseErrno();
int _computeAddressInUseErrno() {
  if (Platform.isWindows) return 10048;
  if (Platform.isMacOS) return 48;
  assert(Platform.isLinux);
  return 98;
}

/// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers
/// and forwards methods to all of them.
///
/// This is useful for serving the same application on multiple network
/// interfaces while still having a unified way of controlling the servers. In
/// particular, it supports serving on both the IPv4 and IPv6 loopback addresses
/// using [HttpMultiServer.loopback].
class HttpMultiServer extends StreamView<HttpRequest> implements HttpServer {
  /// The wrapped servers.
  final Set<HttpServer> _servers;

  /// Returns the default value of the `Server` header for all responses
  /// generated by each server.
  ///
  /// If the wrapped servers have different default values, it's not defined
  /// which value is returned.
  String get serverHeader => _servers.first.serverHeader;
  set serverHeader(String value) {
    for (var server in _servers) {
      server.serverHeader = value;
    }
  }

  /// Returns the default set of headers added to all response objects.
  ///
  /// If the wrapped servers have different default headers, it's not defined
  /// which header is returned for accessor methods.
  final HttpHeaders defaultResponseHeaders;

  Duration get idleTimeout => _servers.first.idleTimeout;
  set idleTimeout(Duration value) {
    for (var server in _servers) {
      server.idleTimeout = value;
    }
  }

  bool get autoCompress => _servers.first.autoCompress;
  set autoCompress(bool value) {
    for (var server in _servers) {
      server.autoCompress = value;
    }
  }

  /// Returns the port that one of the wrapped servers is listening on.
  ///
  /// If the wrapped servers are listening on different ports, it's not defined
  /// which port is returned.
  int get port => _servers.first.port;

  /// Returns the address that one of the wrapped servers is listening on.
  ///
  /// If the wrapped servers are listening on different addresses, it's not
  /// defined which address is returned.
  InternetAddress get address => _servers.first.address;

  set sessionTimeout(int value) {
    for (var server in _servers) {
      server.sessionTimeout = value;
    }
  }

  /// Creates an [HttpMultiServer] wrapping [servers].
  ///
  /// All [servers] should have the same configuration and none should be
  /// listened to when this is called.
  HttpMultiServer(Iterable<HttpServer> servers)
      : _servers = servers.toSet(),
        defaultResponseHeaders = new MultiHeaders(
            servers.map((server) => server.defaultResponseHeaders)),
        super(mergeStreams(servers));

  /// Creates an [HttpServer] listening on all available loopback addresses for
  /// this computer.
  ///
  /// If this computer supports both IPv4 and IPv6, this returns an
  /// [HttpMultiServer] listening to [port] on both loopback addresses.
  /// Otherwise, it returns a normal [HttpServer] listening only on the IPv4
  /// address.
  ///
  /// If [port] is 0, the same ephemeral port is used for both the IPv4 and IPv6
  /// addresses.
  static Future<HttpServer> loopback(int port, {int backlog}) {
    if (backlog == null) backlog = 0;

    return _loopback(port, (address, port) =>
        HttpServer.bind(address, port, backlog: backlog));
  }

  /// Like [loopback], but supports HTTPS requests.
  ///
  /// The certificate with nickname or distinguished name (DN) [certificateName]
  /// is looked up in the certificate database, and is used as the server
  /// certificate. If [requestClientCertificate] is true, the server will
  /// request clients to authenticate with a client certificate.
  static Future<HttpServer> loopbackSecure(int port, {int backlog,
      String certificateName, bool requestClientCertificate: false}) {
    if (backlog == null) backlog = 0;

    return _loopback(port, (address, port) =>
        HttpServer.bindSecure(address, port, backlog: backlog,
            certificateName: certificateName,
            requestClientCertificate: requestClientCertificate));
  }

  /// A helper method for initializing loopback servers.
  ///
  /// [bind] should forward to either [HttpServer.bind] or
  /// [HttpServer.bindSecure].
  static Future<HttpServer> _loopback(int port,
      Future<HttpServer> bind(InternetAddress address, int port),
      [int remainingRetries]) {
    if (remainingRetries == null) remainingRetries = 5;

    return Future.wait([
      supportsIpV6,
      bind(InternetAddress.LOOPBACK_IP_V4, port)
    ]).then((results) {
      var supportsIpV6 = results[0];
      var v4Server = results[1];

      if (!supportsIpV6) return v4Server;

      // Reuse the IPv4 server's port so that if [port] is 0, both servers use
      // the same ephemeral port.
      return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port)
          .then((v6Server) {
        return new HttpMultiServer([v4Server, v6Server]);
      }).catchError((error) {
        if (error is! SocketException) throw error;
        if (error.osError.errorCode != _addressInUseErrno) throw error;
        if (port != 0) throw error;
        if (remainingRetries == 0) throw error;

        // A port being available on IPv4 doesn't necessarily mean that the same
        // port is available on IPv6. If it's not (which is rare in practice),
        // we try again until we find one that's available on both.
        v4Server.close();
        return _loopback(port, bind, remainingRetries - 1);
      });
    });
  }

  Future close({bool force: false}) =>
      Future.wait(_servers.map((server) => server.close(force: force)));

  /// Returns an HttpConnectionsInfo object summarizing the total number of
  /// current connections handled by all the servers.
  HttpConnectionsInfo connectionsInfo() {
    var info = new HttpConnectionsInfo();
    for (var server in _servers) {
      var subInfo = server.connectionsInfo();
      info.total += subInfo.total;
      info.active += subInfo.active;
      info.idle += subInfo.idle;
      info.closing += subInfo.closing;
    }
    return info;
  }
}
