// PureLife Device Provisioning Protocol, version 1.0 (Draft).
//
// Endpoint `pld-config`: the pending PLD configuration (Server URL, NTP
// servers, DNS servers). Values set here are held in memory only. They are
// persisted by Commit on the `pld-ctrl` endpoint.
// See the Device Provisioning Protocol (pld-provisioning.html), section 9.2.

syntax = "proto3";

package pld;

import "pld_constants.proto";

// Type of the message carried in `ConfigPayload`.
enum ConfigMsgType {
  // Not set. A payload with this type is invalid.
  CONFIG_MSG_TYPE_UNSPECIFIED = 0;

  // Provisioner to Device: `SetConfigCommand`.
  CONFIG_MSG_TYPE_SET_CONFIG_COMMAND = 1;

  // Device to Provisioner: `SetConfigResponse`.
  CONFIG_MSG_TYPE_SET_CONFIG_RESPONSE = 2;

  // Provisioner to Device: `GetConfigCommand`.
  CONFIG_MSG_TYPE_GET_CONFIG_COMMAND = 3;

  // Device to Provisioner: `GetConfigResponse`.
  CONFIG_MSG_TYPE_GET_CONFIG_RESPONSE = 4;
}

// A list of strings with presence.
//
// A repeated field cannot express "not sent". Wrapping the list in a message
// makes the difference visible: an unset `StringList` leaves the pending
// value unchanged, a set `StringList` replaces it, and a set `StringList`
// with no entries clears it.
message StringList {
  // The entries, in order.
  repeated string entries = 1;
}

// The PLD configuration as a whole. Used in `GetConfigResponse`.
message Config {
  // Server URL. Absolute URL with scheme `https` or `http`, no userinfo, no
  // query, no fragment, at most 128 bytes. A trailing slash is invalid.
  // Required for a Commit; the lists below may stay empty. A
  // path prefix is allowed. The Device appends the paths of the Device Messaging
  // Protocol (`/pld/v1/...`) to it. With `http` the connection is
  // unencrypted.
  //
  // Example: `https://cloud.smart-altern.de`
  string server_url = 1;

  // NTP servers, tried in order. 0 to 3 entries, each a host name or IPv4
  // literal of at most 40 bytes. Empty: the Device uses the NTP servers
  // offered by DHCP, or NTP servers defined by the Manufacturer if DHCP
  // offers none.
  repeated string ntp_servers = 2;

  // DNS servers, used instead of the ones offered by DHCP. 0 to 3 entries,
  // each an IPv4 literal (at most 15 bytes) or, if the Device announces the
  // `ipv6` capability, an IPv6 literal (at most 45 bytes). Empty: the
  // Device uses the DNS servers offered by DHCP.
  repeated string dns_servers = 3;
}

// Sets pending configuration values.
//
// Fields that are not present leave the pending value unchanged. This
// allows the Provisioner to split the configuration over several commands.
// The Device validates every present field and rejects the whole command
// with `STATUS_INVALID_ARGUMENT` if any field is invalid; in that case no
// pending value changes.
message SetConfigCommand {
  // Optional. New Server URL. Constraints as in `Config.server_url`.
  //
  // Declared `optional` so that "not sent" (leave unchanged) can be
  // distinguished from an empty string (invalid).
  optional string server_url = 1;

  // Optional. New NTP server list. Constraints as in `Config.ntp_servers`.
  // Unset: unchanged. Set: replaces the pending list. Set and empty: use
  // DHCP.
  StringList ntp_servers = 2;

  // Optional. New DNS server list. Constraints as in `Config.dns_servers`.
  // Unset: unchanged. Set: replaces the pending list. Set and empty: use
  // DHCP.
  StringList dns_servers = 3;
}

// Result of `SetConfigCommand`.
message SetConfigResponse {
  // Required. Result of the command.
  Status status = 1;

  // Optional. Human readable detail for logs and support, English, at most
  // 64 bytes. Names the offending field on `STATUS_INVALID_ARGUMENT`.
  string detail = 2;
}

// Requests the pending configuration. Has no fields.
message GetConfigCommand {}

// The pending configuration and the commit state.
message GetConfigResponse {
  // 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. The pending configuration. Fields that have not been set yet
  // are empty.
  Config config = 3;

  // Required. True if a Commit has happened in this Provisioning period.
  bool committed = 4;
}

// Payload of the `pld-config` endpoint.
message ConfigPayload {
  // Required. Identifies which member of `payload` is set.
  ConfigMsgType msg = 1;

  // The command or response. Exactly one member is set.
  oneof payload {
    // Set when `msg` is `CONFIG_MSG_TYPE_SET_CONFIG_COMMAND`.
    SetConfigCommand set_config_command = 10;

    // Set when `msg` is `CONFIG_MSG_TYPE_SET_CONFIG_RESPONSE`.
    SetConfigResponse set_config_response = 11;

    // Set when `msg` is `CONFIG_MSG_TYPE_GET_CONFIG_COMMAND`.
    GetConfigCommand get_config_command = 12;

    // Set when `msg` is `CONFIG_MSG_TYPE_GET_CONFIG_RESPONSE`.
    GetConfigResponse get_config_response = 13;
  }
}
