// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// API for communicating with a Google Cast device over an authenticated
// channel.
namespace cast.channel {
  // The state of the channel.
  enum ReadyState {
    // The channel is connecting.
    connecting,
    // The channel is open and available for messaging.
    open,
    // The channel is closing.
    closing,
    // The channel is closed.
    closed
  };

  // Error conditions that the channel may encounter.  All error conditions
  // are terminal.  When an error condition is encountered the API will:
  // (1) Transition the channel to readyState == 'closed'.
  // (2) Set ChannelInfo.lastError to the error condition.
  // (3) Fire an onError event with the error condition.
  // (4) Fire an onClose event.
  enum ChannelError {
    // cast.channel.send() was called when ChannelInfo.readyState != 'open'.
    channel_not_open,
    // Authentication was requested and the receiver could not be
    // authenticated (invalid signature, invalid handhake, TLS error, etc.)
    authentication_error,
    // A new channel could not be created for reasons unrelated to
    // authentication (e.g., there is already an open channel to the same URL).
    connect_error,
    // There was an error writing or reading from the underlying socket.
    socket_error,
    // A transport level occurred (like an unparseable message).
    transport_error,
    // The client attempted to send an unsupported message type through the
    // channel.
    invalid_message,
    // An invalid channel id was passed.
    invalid_channel_id,
    // The connection could not be established before timing out.
    connect_timeout,
    // The receiving end became unresponsive.
    ping_timeout,
    // Unspecified error.
    unknown
  };

  // Authentication methods that may be required to connect to a Cast receiver.
  enum ChannelAuthType {
    // SSL over TCP.
    ssl,
    // SSL over TCP with challenge and receiver signature verification.
    ssl_verified
  };

  // Describes the information needed to connect to a Cast receiver.
  // This replaces the prior use of cast:// and casts:// URLs.
  dictionary ConnectInfo {
    // The IPV4 address of the Cast receiver, e.g. '198.1.0.2'.
    // TODO(mfoltz): Investigate whether IPV6 addresses "just work."
    DOMString ipAddress;

    // The port number to connect to, 0-65535.
    long port;

    // The amount of time to wait in milliseconds before stopping the
    // connection process. Timeouts are disabled if the value is zero.
    // The default timeout is 8000ms.
    long? timeout;

    // The authentication method required for the channel.
    ChannelAuthType auth;

    // ------------------------------------------------------------------------
    // Both pingInterval and livenessTimeout must be set to enable keep-alive
    // handling.

    // The amount of time to wait in milliseconds before sending pings
    // to idle channels.
    long? pingInterval;

    // The maximum amount of idle time allowed before a channel is closed.
    long? livenessTimeout;

    // If set, CastDeviceCapability bitmask values describing capability of the
    // cast device.
    long? capabilities;
  };

  // Describes the state of a channel to a Cast receiver.
  dictionary ChannelInfo {
    // Id for the channel.
    long channelId;

    // Connection information that was used to establish the channel to the
    // receiver.
    ConnectInfo connectInfo;

    // The current state of the channel.
    ReadyState readyState;

    // If set, the last error condition encountered by the channel.
    ChannelError? errorState;

    // If true, keep-alive messages are handled automatically by the channel.
    boolean keepAlive;

    // Whether the channel is audio only as identified by the device
    // certificate during channel authentication.
    boolean audioOnly;
  };

  // Describes a message sent or received over the channel.  Currently only
  // string messages are supported, although ArrayBuffer and Blob types may be
  // supported in the future.
  dictionary MessageInfo {
    // The message namespace.  A namespace is a URN of the form
    // urn:cast-x:<namespace> that is used to interpret and route Cast messages.
    DOMString namespace_;

    // source and destination ids identify the origin and destination of the
    // message.  They are used to route messages between endpoints that share a
    // device-to-device channel.
    //
    // For messages between applications:
    //   - The sender application id is a unique identifier generated on behalf
    //     of the sender application.
    //   - The receiver id is always the the session id for the application.
    //
    // For messages to or from the sender or receiver platform, the special ids
    // 'sender-0' and 'receiver-0' can be used.
    //
    // For messages intended for all endpoints using a given channel, the
    // wildcard destination_id '*' can be used.
    DOMString sourceId;
    DOMString destinationId;

    // The content of the message.  Must be either a string or an ArrayBuffer.
    any data;
  };

  // Describes a terminal error encountered by the channel with details of the
  // error that caused the channel to be closed.  One or more of the optional
  // fields may be set with specific error codes from the underlying
  // implementation.
  dictionary ErrorInfo {
    // The type of error encountered by the channel.
    ChannelError errorState;

    // The event that was occurring when the error happened.  Values are defined
    // in the enum EventType in logging.proto.
    long? eventType;

    // An error encountered when processing the authentication handshake.
    // Values are defined in the enum ChallengeReplyErrorType in logging.proto.
    long? challengeReplyErrorType;

    // A return value from the underlying net:: socket libraries. Values are
    // defined in net/base/net_error_list.h.
    long? netReturnValue;

    // An error code returned by NSS. Values are defined in secerr.h.
    long? nssErrorCode;
  };

  // Callback holding the result of a channel operation.
  callback ChannelInfoCallback = void (ChannelInfo result);

  // Callback from <code>getLogs</code> method.
  // |log|: compressed serialized raw bytes containing the logs.
  // The log is formatted using protocol buffer.
  // See extensions/browser/api/cast_channel/logging.proto for definition.
  // Compression is in gzip format.
  callback GetLogsCallback = void (ArrayBuffer log);

  // Callback from <code>setAuthorityKeys</code> method.
  callback SetAuthorityKeysCallback = void ();

  interface Functions {
    // Opens a new channel to the Cast receiver specified by connectInfo.  Only
    // one channel may be connected to same receiver from the same extension at
    // a time.  If the open request is successful, the callback will be invoked
    // with a ChannelInfo with readyState == 'connecting'.  If unsuccessful, the
    // callback will be invoked with a ChannelInfo with channel.readyState ==
    // 'closed', channel.errorState will be set to the error condition, and
    // onError will be fired with error details.
    static void open(ConnectInfo connectInfo,
                     ChannelInfoCallback callback);

    // Sends a message on the channel and invokes callback with the resulting
    // channel status.  The channel must be in readyState == 'open'.  If
    // unsuccessful, channel.readyState will be set to 'closed',
    // channel.errorState will be set to the error condition, and onError will
    // be fired with error details.
    static void send(ChannelInfo channel,
                     MessageInfo message,
                     ChannelInfoCallback callback);

    // Requests that the channel be closed and invokes callback with the
    // resulting channel status.  The channel must be in readyState == 'open' or
    // 'connecting'.  If successful, onClose will be fired with readyState ==
    // 'closed'.  If unsuccessful, channel.readyState will be set to 'closed',
    // and channel.errorState will be set to the error condition.
    static void close(ChannelInfo channel,
                      ChannelInfoCallback callback);

    // Get logs in compressed serialized format. See GetLogsCallback for
    // details.
    // |callback|: If successful, |callback| is invoked with data. Otherwise,
    // an error will be raised.
    static void getLogs(GetLogsCallback callback);

    // Sets trusted certificate authorities where |signature| is a base64
    // encoded RSA-PSS signature and |keys| is base64 encoded AuthorityKeys
    // protobuf.
    static void setAuthorityKeys(DOMString keys,
                                 DOMString signature,
                                 SetAuthorityKeysCallback callback);
  };

  // Events on the channel.
  interface Events {
    // Fired when a message is received on an open channel.
    static void onMessage(ChannelInfo channel,
                          MessageInfo message);

    // Fired when an error occurs as a result of a channel operation or a
    // network event. |error| contains details of the error.
    static void onError(ChannelInfo channel, ErrorInfo error);
  };
};
