// PureLife Device Provisioning Protocol, version 1.0 (Draft).
//
// Endpoint `pld-check`: the Server check. Verifies from the Device's point
// of view that the Server is reachable with the pending configuration. The
// check is asynchronous: the Provisioner starts it and polls the result.
// See the Device Provisioning Protocol (pld-provisioning.html), section 10.

syntax = "proto3";

package pld;

import "pld_constants.proto";

// Type of the message carried in `CheckPayload`.
enum CheckMsgType {
  // Not set. A payload with this type is invalid.
  CHECK_MSG_TYPE_UNSPECIFIED = 0;

  // Provisioner to Device: `StartCheckCommand`.
  CHECK_MSG_TYPE_START_CHECK_COMMAND = 1;

  // Device to Provisioner: `StartCheckResponse`.
  CHECK_MSG_TYPE_START_CHECK_RESPONSE = 2;

  // Provisioner to Device: `GetCheckStatusCommand`.
  CHECK_MSG_TYPE_GET_CHECK_STATUS_COMMAND = 3;

  // Device to Provisioner: `GetCheckStatusResponse`.
  CHECK_MSG_TYPE_GET_CHECK_STATUS_RESPONSE = 4;
}

// Overall state of the Server check.
enum CheckState {
  // Not set. A response with this state is invalid.
  CHECK_STATE_UNSPECIFIED = 0;

  // No check has been started in this session.
  CHECK_STATE_IDLE = 1;

  // A check is running. Poll again.
  CHECK_STATE_RUNNING = 2;

  // The check has finished. `stages` holds the result.
  CHECK_STATE_DONE = 3;
}

// The stages of the Server check, in the order they run.
enum CheckStage {
  // Not set. A stage result with this stage is invalid.
  CHECK_STAGE_UNSPECIFIED = 0;

  // The Wi-Fi station is connected and has an IP address.
  CHECK_STAGE_WIFI = 1;

  // The host of the Server URL resolves using the DNS servers in effect
  // (configured, or from DHCP).
  CHECK_STAGE_DNS = 2;

  // The clock is synchronised with one of the NTP servers in effect
  // (configured, from DHCP, or Manufacturer default).
  CHECK_STAGE_NTP = 3;

  // A TLS connection to the Server host is established and the certificate
  // chain validates against the Device's store of public CA certificates.
  // Skipped when the Server URL uses the scheme `http`.
  CHECK_STAGE_TLS = 4;

  // Authentication (`POST /pld/v1/auth`) and bootstrap
  // (`GET /pld/v1/bootstrap`) of the Device Messaging Protocol both succeed
  // with HTTP status 200. As a side effect the Device is registered on the
  // Server.
  CHECK_STAGE_SERVER = 5;

  // A connection to the broker from the bootstrap response succeeds with
  // the returned credentials and is closed again normally. Nothing is
  // published.
  CHECK_STAGE_MQTT = 6;
}

// Result of a single stage.
enum StageState {
  // Not set. A stage result with this state is invalid.
  STAGE_STATE_UNSPECIFIED = 0;

  // The stage has not started yet.
  STAGE_STATE_PENDING = 1;

  // The stage is running.
  STAGE_STATE_RUNNING = 2;

  // The stage succeeded.
  STAGE_STATE_OK = 3;

  // The stage failed. `StageResult.error` says why.
  STAGE_STATE_FAILED = 4;

  // The stage did not run because an earlier stage failed.
  STAGE_STATE_SKIPPED = 5;
}

// Reason for a failed stage.
enum CheckError {
  // No error. The default for stages that did not fail.
  CHECK_ERROR_NONE = 0;

  // Stage WIFI: no connection or no IP address.
  CHECK_ERROR_WIFI_NOT_CONNECTED = 1;

  // Stage DNS: name resolution failed.
  CHECK_ERROR_DNS_FAILED = 2;

  // Stage NTP: no NTP server in effect answered.
  CHECK_ERROR_NTP_UNREACHABLE = 3;

  // Stage TLS: TCP or TLS handshake failed for a reason other than
  // certificate validation.
  CHECK_ERROR_TLS_CONNECT_FAILED = 4;

  // Stage TLS: the certificate chain does not validate against the CA
  // store.
  CHECK_ERROR_TLS_CERT_UNTRUSTED = 5;

  // Stage TLS: the certificate is not yet valid or has expired according
  // to the Device clock.
  CHECK_ERROR_TLS_CERT_INVALID_TIME = 6;

  // Stage TLS: the certificate does not match the host name.
  CHECK_ERROR_TLS_HOSTNAME_MISMATCH = 7;

  // Stage SERVER: the request could not be sent or no response was
  // received.
  CHECK_ERROR_HTTP_CONNECT_FAILED = 8;

  // Stage SERVER: a response was received with a status other than 200.
  // `StageResult.http_status` holds it.
  CHECK_ERROR_HTTP_STATUS = 9;

  // Stage SERVER: a response was received but it is not a valid
  // authentication or bootstrap response.
  CHECK_ERROR_HTTP_INVALID_RESPONSE = 10;

  // Any stage: the stage exceeded its time budget.
  CHECK_ERROR_TIMEOUT = 11;

  // Any stage: any other error. `StageResult.detail` should explain.
  CHECK_ERROR_INTERNAL = 12;

  // Stage MQTT: TCP or TLS connection to the broker failed, or no CONNACK.
  CHECK_ERROR_MQTT_CONNECT_FAILED = 13;

  // Stage MQTT: the broker refused the credentials (CONNACK reason code
  // other than success).
  CHECK_ERROR_MQTT_NOT_AUTHORIZED = 14;
}

// Result of one stage of the Server check.
message StageResult {
  // Required. The stage.
  CheckStage stage = 1;

  // Required. State of the stage.
  StageState result = 2;

  // Reason for the failure. `CHECK_ERROR_NONE` unless `result` is
  // `STAGE_STATE_FAILED`.
  CheckError error = 3;

  // HTTP status code. Set only when `error` is `CHECK_ERROR_HTTP_STATUS`;
  // 0 otherwise.
  uint32 http_status = 4;

  // Optional. Human readable detail, at most 32 bytes, for example the
  // resolved address or the TLS error string of the platform.
  string detail = 5;
}

// Starts the Server check with the pending configuration.
//
// Requires a complete pending configuration and a connected Wi-Fi station
// (`STATUS_INVALID_STATE` otherwise). A running check answers
// `STATUS_BUSY`. The whole check finishes within 60 seconds. Has no fields.
message StartCheckCommand {}

// Result of `StartCheckCommand`.
message StartCheckResponse {
  // Required. Result of the command.
  Status status = 1;

  // Optional. Human readable detail for logs and support, English, at most
  // 64 bytes. MUST be empty when `status` is `STATUS_OK`.
  string detail = 2;
}

// Requests the state and result of the Server check. Has no fields.
message GetCheckStatusCommand {}

// State and result of the Server check.
message GetCheckStatusResponse {
  // Required. Result of the command.
  Status status = 1;

  // Optional. Human readable detail for logs and support, English, at most
  // 64 bytes. MUST be empty when `status` is `STATUS_OK`.
  string detail = 2;

  // Required. Overall state of the check.
  CheckState state = 3;

  // One entry per stage, in the order of `CheckStage`. Empty while `state`
  // is `CHECK_STATE_IDLE`.
  repeated StageResult stages = 4;
}

// Payload of the `pld-check` endpoint.
message CheckPayload {
  // Required. Identifies which member of `payload` is set.
  CheckMsgType msg = 1;

  // The command or response. Exactly one member is set.
  oneof payload {
    // Set when `msg` is `CHECK_MSG_TYPE_START_CHECK_COMMAND`.
    StartCheckCommand start_check_command = 10;

    // Set when `msg` is `CHECK_MSG_TYPE_START_CHECK_RESPONSE`.
    StartCheckResponse start_check_response = 11;

    // Set when `msg` is `CHECK_MSG_TYPE_GET_CHECK_STATUS_COMMAND`.
    GetCheckStatusCommand get_check_status_command = 12;

    // Set when `msg` is `CHECK_MSG_TYPE_GET_CHECK_STATUS_RESPONSE`.
    GetCheckStatusResponse get_check_status_response = 13;
  }
}
