/*
 *     Copyright 2022 The Dragonfly Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

syntax = "proto3";

package scheduler.v2;

import "pkg/apis/common/v2/common.proto";
import "pkg/apis/errordetails/v2/errordetails.proto";
import "validate/validate.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/duration.proto";

option go_package = "d7y.io/api/v2/pkg/apis/scheduler/v2;scheduler";

// RegisterPeerRequest represents peer registered request of AnnouncePeerRequest.
message RegisterPeerRequest {
  // Download information.
  common.v2.Download download = 1 [(validate.rules).message.required = true];
}

// DownloadPeerStartedRequest represents peer download started request of AnnouncePeerRequest.
message DownloadPeerStartedRequest {
}

// DownloadPeerBackToSourceStartedRequest represents peer download back-to-source started request of AnnouncePeerRequest.
message DownloadPeerBackToSourceStartedRequest {
  // The description of the back-to-source reason.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// ReschedulePeerRequest represents reschedule request of AnnouncePeerRequest.
message ReschedulePeerRequest {
  // Candidate parent ids.
  repeated common.v2.Peer candidate_parents = 1;

  // The description of the reschedule reason.
  optional string description = 2 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPeerFinishedRequest represents peer download finished request of AnnouncePeerRequest.
message DownloadPeerFinishedRequest {
  reserved 1;
  reserved "content_length";

  reserved 2;
  reserved "piece_count";
}

// DownloadPeerBackToSourceFinishedRequest represents peer download back-to-source finished request of AnnouncePeerRequest.
message DownloadPeerBackToSourceFinishedRequest {
  reserved 1;
  reserved "content_length";

  reserved 2;
  reserved "piece_count";
}

// DownloadPeerFailedRequest represents peer download failed request of AnnouncePeerRequest.
message DownloadPeerFailedRequest {
  // The description of the download failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPeerBackToSourceFailedRequest represents peer download back-to-source failed request of AnnouncePeerRequest.
message DownloadPeerBackToSourceFailedRequest {
  // The description of the download back-to-source failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPieceFinishedRequest represents piece download finished request of AnnouncePeerRequest.
message DownloadPieceFinishedRequest {
  // Piece info.
  common.v2.Piece piece = 1 [(validate.rules).message.required = true];
}

// DownloadPieceBackToSourceFinishedRequest represents piece download back-to-source finished request of AnnouncePeerRequest.
message DownloadPieceBackToSourceFinishedRequest {
  // Piece info.
  common.v2.Piece piece = 1 [(validate.rules).message.required = true];
}

// DownloadPieceFailedRequest downloads piece failed request of AnnouncePeerRequest.
message DownloadPieceFailedRequest {
  // Piece number.
  optional uint32 piece_number = 1;
  // Parent id.
  string parent_id = 2 [(validate.rules).string.min_len = 1];
  // Temporary indicates whether the error is temporary.
  bool temporary = 3;
}

// DownloadPieceBackToSourceFailedRequest downloads piece back-to-source failed request of AnnouncePeerRequest.
message DownloadPieceBackToSourceFailedRequest {
  // Piece number.
  optional uint32 piece_number = 1;

  oneof response {
    option (validate.required) = true;

    errordetails.v2.Backend backend = 2;
    errordetails.v2.Unknown unknown = 3;
  }
}

// AnnouncePeerRequest represents request of AnnouncePeer.
message AnnouncePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];

  oneof request {
    option (validate.required) = true;

    RegisterPeerRequest register_peer_request = 4;
    DownloadPeerStartedRequest download_peer_started_request = 5;
    DownloadPeerBackToSourceStartedRequest download_peer_back_to_source_started_request = 6;
    ReschedulePeerRequest reschedule_peer_request = 7;
    DownloadPeerFinishedRequest download_peer_finished_request = 8;
    DownloadPeerBackToSourceFinishedRequest download_peer_back_to_source_finished_request = 9;
    DownloadPeerFailedRequest download_peer_failed_request = 10;
    DownloadPeerBackToSourceFailedRequest download_peer_back_to_source_failed_request = 11;
    DownloadPieceFinishedRequest download_piece_finished_request = 12;
    DownloadPieceBackToSourceFinishedRequest download_piece_back_to_source_finished_request = 13;
    DownloadPieceFailedRequest download_piece_failed_request = 14;
    DownloadPieceBackToSourceFailedRequest download_piece_back_to_source_failed_request = 15;
  }
}

// EmptyTaskResponse represents empty task response of AnnouncePeerResponse.
message EmptyTaskResponse {
}

// NormalTaskResponse represents normal task response of AnnouncePeerResponse.
message NormalTaskResponse {
  // Candidate parents.
  repeated common.v2.Peer candidate_parents = 1 [(validate.rules).repeated.min_items = 1];
}

// NeedBackToSourceResponse represents need back-to-source response of AnnouncePeerResponse.
message NeedBackToSourceResponse {
  // The description of the back-to-source reason.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// AnnouncePeerResponse represents response of AnnouncePeer.
message AnnouncePeerResponse {
  oneof response {
    option (validate.required) = true;

    EmptyTaskResponse empty_task_response = 1;
    NormalTaskResponse normal_task_response = 2;
    NeedBackToSourceResponse need_back_to_source_response = 3;
  }
}

// StatPeerRequest represents request of StatPeer.
message StatPeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// DeletePeerRequest represents request of DeletePeer.
message DeletePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// StatTaskRequest represents request of StatTask.
message StatTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// DeleteTaskRequest represents request of DeleteTask.
message DeleteTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// AnnounceHostRequest represents request of AnnounceHost.
message AnnounceHostRequest {
  // Host info.
  common.v2.Host host = 1 [(validate.rules).message.required = true];
  // The interval between dfdaemon announces to scheduler.
  optional google.protobuf.Duration interval = 2;
}

// ListHostsRequest represents request of ListHosts.
message ListHostsRequest {
    // Type to filter hosts.
    optional uint32 type = 1;
}

// ListHostsResponse represents response of ListHosts.
message ListHostsResponse {
  // Hosts info.
  repeated common.v2.Host hosts = 1;
}

// DeleteHostRequest represents request of DeleteHost.
message DeleteHostRequest{
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
}

// RegisterCachePeerRequest represents cache peer registered request of AnnounceCachePeerRequest.
message RegisterCachePeerRequest {
   // Download url.
  string url = 1 [(validate.rules).string.uri = true];
  // Digest of the task digest, for example blake3:xxx or sha256:yyy.
  optional string digest = 2 [(validate.rules).string = {pattern: "^(md5:[a-fA-F0-9]{32}|sha1:[a-fA-F0-9]{40}|sha256:[a-fA-F0-9]{64}|sha512:[a-fA-F0-9]{128}|blake3:[a-fA-F0-9]{64}|crc32:[a-fA-F0-9]+)$", ignore_empty: true}];
  // Range is url range of request. If protocol is http, range
  // will set in request header. If protocol is others, range
  // will set in range field.
  optional common.v2.Range range = 3;
  // Task type.
  common.v2.TaskType type = 4 [(validate.rules).enum.defined_only = true];
  // URL tag identifies different task for same url.
  optional string tag = 5;
  // Application of task.
  optional string application = 6;
  // Peer priority.
  common.v2.Priority priority = 7 [(validate.rules).enum.defined_only = true];
  // Filtered query params to generate the task id.
  // When filter is ["Signature", "Expires", "ns"], for example:
  // http://example.com/xyz?Expires=e1&Signature=s1&ns=docker.io and http://example.com/xyz?Expires=e2&Signature=s2&ns=docker.io
  // will generate the same task id.
  // Default value includes the filtered query params of s3, gcs, oss, obs, cos.
  repeated string filtered_query_params = 8;
  // Task request headers.
  map<string, string> request_header = 9;
	// Piece Length is the piece length(bytes) for downloading file. The value needs to
	// be greater than 4MiB (4,194,304 bytes) and less than 64MiB (67,108,864 bytes),
	// for example: 4194304(4mib), 8388608(8mib). If the piece length is not specified,
	// the piece length will be calculated according to the file size.
  optional uint64 piece_length = 10 [(validate.rules).uint64 = {gte: 4194304, lte: 67108864, ignore_empty: true}];
  // File path to be downloaded. If output_path is set, the downloaded file will be saved to the specified path.
  // Dfdaemon will try to create hard link to the output path before starting the download. If hard link creation fails,
  // it will copy the file to the output path after the download is completed.
  // For more details refer to https://github.com/dragonflyoss/design/blob/main/systems-analysis/file-download-workflow-with-hard-link/README.md.
  optional string output_path = 11 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
  // Download timeout.
  optional google.protobuf.Duration timeout = 12;
  // Dfdaemon cannot download the task from the source if disable_back_to_source is true.
  bool disable_back_to_source = 13;
  // Scheduler needs to schedule the task downloads from the source if need_back_to_source is true.
  bool need_back_to_source = 14;
  // certificate_chain is the client certs with DER format for the backend client to download back-to-source.
  repeated bytes certificate_chain = 15;
  // Prefetch pre-downloads all pieces of the task when the download task request is a range request.
  bool prefetch = 16;
  // Object storage protocol information.
  optional common.v2.ObjectStorage object_storage = 17;
  // HDFS protocol information.
  optional common.v2.HDFS hdfs = 18;
  // is_prefetch is the flag to indicate whether the request is a prefetch request.
  bool is_prefetch = 19;
  // need_piece_content is the flag to indicate whether the response needs to return piece content.
  bool need_piece_content = 20;
  // content_for_calculating_task_id is the content used to calculate the task id.
  // If content_for_calculating_task_id is set, use its value to calculate the task ID.
  // Otherwise, calculate the task ID based on url, piece_length, tag, application, and filtered_query_params.
  optional string content_for_calculating_task_id = 21;
  // remote_ip represents the IP address of the client initiating the download request.
  // For proxy requests, it is set to the IP address of the request source.
  // For dfget requests, it is set to the IP address of the dfget.
  optional string remote_ip = 22 [(validate.rules).string = {ip: true, ignore_empty: true}];
  // concurrent_piece_count is the number of pieces that can be downloaded concurrently.
  optional uint32 concurrent_piece_count = 23;
  // Actual piece length by calculating based on the piece_length field and content length.
  optional uint64 actual_piece_length = 24;
  // Actual content length by getting from the backend.
  optional uint64 actual_content_length = 25;
  // Actual piece count by calculating.
  optional uint64 actual_piece_count = 26;
}

// DownloadCachePeerStartedRequest represents cache peer download started request of AnnounceCachePeerRequest.
message DownloadCachePeerStartedRequest {
}

// DownloadCachePeerBackToSourceStartedRequest represents cache peer download back-to-source started request of AnnounceCachePeerRequest.
message DownloadCachePeerBackToSourceStartedRequest {
  // The description of the back-to-source reason.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// RescheduleCachePeerRequest represents reschedule request of AnnounceCachePeerRequest.
message RescheduleCachePeerRequest {
  // Candidate parent ids.
  repeated common.v2.CachePeer candidate_parents = 1;

  // The description of the reschedule reason.
  optional string description = 2 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadCachePeerFinishedRequest represents cache peer download finished request of AnnounceCachePeerRequest.
message DownloadCachePeerFinishedRequest {
  reserved 1;
  reserved "content_length";

  reserved 2;
  reserved "piece_count";
}

// DownloadCachePeerBackToSourceFinishedRequest represents cache peer download back-to-source finished request of AnnounceCachePeerRequest.
message DownloadCachePeerBackToSourceFinishedRequest {
  reserved 1;
  reserved "content_length";

  reserved 2;
  reserved "piece_count";
}

// DownloadCachePeerFailedRequest represents cache peer download failed request of AnnounceCachePeerRequest.
message DownloadCachePeerFailedRequest {
  // The description of the download failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadCachePeerBackToSourceFailedRequest represents cache peer download back-to-source failed request of AnnounceCachePeerRequest.
message DownloadCachePeerBackToSourceFailedRequest {
  // The description of the download back-to-source failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// AnnounceCachePeerRequest represents request of AnnounceCachePeer.
message AnnounceCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];

  oneof request {
    option (validate.required) = true;

    RegisterCachePeerRequest register_cache_peer_request = 4;
    DownloadCachePeerStartedRequest download_cache_peer_started_request = 5;
    DownloadCachePeerBackToSourceStartedRequest download_cache_peer_back_to_source_started_request = 6;
    RescheduleCachePeerRequest reschedule_cache_peer_request = 7;
    DownloadCachePeerFinishedRequest download_cache_peer_finished_request = 8;
    DownloadCachePeerBackToSourceFinishedRequest download_cache_peer_back_to_source_finished_request = 9;
    DownloadCachePeerFailedRequest download_cache_peer_failed_request = 10;
    DownloadCachePeerBackToSourceFailedRequest download_cache_peer_back_to_source_failed_request = 11;
    DownloadPieceFinishedRequest download_piece_finished_request = 12;
    DownloadPieceBackToSourceFinishedRequest download_piece_back_to_source_finished_request = 13;
    DownloadPieceFailedRequest download_piece_failed_request = 14;
    DownloadPieceBackToSourceFailedRequest download_piece_back_to_source_failed_request = 15;
  }
}

// EmptyCacheTaskResponse represents empty cache task response of AnnounceCachePeerResponse.
message EmptyCacheTaskResponse {
}

// NormalCacheTaskResponse represents normal cache task response of AnnounceCachePeerResponse.
message NormalCacheTaskResponse {
  // Candidate parents.
  repeated common.v2.CachePeer candidate_parents = 1 [(validate.rules).repeated.min_items = 1];
}

// AnnounceCachePeerResponse represents response of AnnounceCachePeer.
message AnnounceCachePeerResponse {
  oneof response {
    option (validate.required) = true;

    EmptyCacheTaskResponse empty_cache_task_response = 1;
    NormalCacheTaskResponse normal_cache_task_response = 2;
    NeedBackToSourceResponse need_back_to_source_response = 3;
  }
}

// StatCachePeerRequest represents request of StatCachePeer.
message StatCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// DeleteCachePeerRequest represents request of DeleteCachePeer.
message DeleteCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// StatCacheTaskRequest represents request of StatCacheTask.
message StatCacheTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// DeleteCacheTaskRequest represents request of DeleteCacheTask.
message DeleteCacheTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// RegisterPersistentPeerRequest represents persistent peer registered request of AnnouncePersistentPeerRequest.
message RegisterPersistentPeerRequest {
  // This is the key of the object storage where the persistent task will be stored,
  // for example: `file.txt` or `dir/file.txt`. The combination of object_storage_key,
  // object_storage.endpoint and object_storage.region must be unique, because
  // the persistent task cannot be overwritten once it is uploaded.
  string object_storage_key = 1 [(validate.rules).string.min_len = 1];
    // Object storage protocol information.
  common.v2.ObjectStorage object_storage = 2 [(validate.rules).message.required = true];
  // Persistent represents whether the persistent task is persistent.
  // If the persistent task is persistent, the persistent peer will
  // not be deleted when dfdaemon runs garbage collection.
  bool persistent = 3;
  // Tag is used to distinguish different persistent tasks.
  optional string tag = 4;
  // Application of task.
  optional string application = 5;
  // Task piece length, the value needs to be greater than or equal to 4194304(4MiB)
  uint64 piece_length = 6 [(validate.rules).uint64.gte = 4194304];
  // File path to be exported.
  optional string output_path = 7 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
  // Download timeout.
  optional google.protobuf.Duration timeout = 8;
  // concurrent_piece_count is the number of pieces that can be downloaded concurrently.
  optional uint32 concurrent_piece_count = 9;
  // Task piece count.
  uint64 piece_count = 10;
}

// DownloadPersistentPeerStartedRequest represents persistent peer download started request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerStartedRequest {
}

// DownloadPersistentPeerBackToSourceStartedRequest represents cache peer download back-to-source started request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerBackToSourceStartedRequest {
  // The description of the back-to-source reason.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// ReschedulePersistentPeerRequest represents reschedule request of AnnouncePersistentPeerRequest.
message ReschedulePersistentPeerRequest {
  // Candidate parent ids.
  repeated common.v2.PersistentPeer candidate_parents = 1;

  // The description of the reschedule reason.
  optional string description = 2 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPersistentPeerFinishedRequest represents persistent peer download finished request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerFinishedRequest {
}

// DownloadPersistentPeerBackToSourceFinishedRequest represents cache peer download back-to-source finished request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerBackToSourceFinishedRequest {
}

// DownloadPersistentPeerFailedRequest represents persistent peer download failed request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerFailedRequest {
  // The description of the download failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPersistentPeerBackToSourceFailedRequest represents cache peer download back-to-source failed request of AnnouncePersistentPeerRequest.
message DownloadPersistentPeerBackToSourceFailedRequest {
  // The description of the download back-to-source failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// AnnouncePersistentPeerRequest represents request of AnnouncePersistentPeer.
message AnnouncePersistentPeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];

  oneof request {
    option (validate.required) = true;

    RegisterPersistentPeerRequest register_persistent_peer_request = 4;
    DownloadPersistentPeerStartedRequest download_persistent_peer_started_request = 5;
    DownloadPersistentPeerBackToSourceStartedRequest download_persistent_peer_back_to_source_started_request = 6;
    ReschedulePersistentPeerRequest reschedule_persistent_peer_request = 7;
    DownloadPersistentPeerFinishedRequest download_persistent_peer_finished_request = 8;
    DownloadPersistentPeerBackToSourceFinishedRequest download_persistent_peer_back_to_source_finished_request = 9;
    DownloadPersistentPeerFailedRequest download_persistent_peer_failed_request = 10;
    DownloadPersistentPeerBackToSourceFailedRequest download_persistent_peer_back_to_source_failed_request = 11;
    DownloadPieceFinishedRequest download_piece_finished_request = 12;
    DownloadPieceBackToSourceFinishedRequest download_piece_back_to_source_finished_request = 13;
    DownloadPieceFailedRequest download_piece_failed_request = 14;
    DownloadPieceBackToSourceFailedRequest download_piece_back_to_source_failed_request = 15;
  }
}

// EmptyPersistentTaskResponse represents empty persistent task response of AnnouncePersistentPeerResponse.
message EmptyPersistentTaskResponse {
}

// NormalPersistentTaskResponse represents normal persistent task response of AnnouncePersistentPeerResponse.
message NormalPersistentTaskResponse {
  // Candidate parents.
  repeated common.v2.PersistentPeer candidate_parents = 1 [(validate.rules).repeated.min_items = 1];
}

// AnnouncePersistentPeerResponse represents response of AnnouncePersistentPeer.
message AnnouncePersistentPeerResponse {
  oneof response {
    option (validate.required) = true;

    EmptyPersistentTaskResponse empty_persistent_task_response = 1;
    NormalPersistentTaskResponse normal_persistent_task_response = 2;
    NeedBackToSourceResponse need_back_to_source_response = 3;
  }
}

// StatPersistentPeerRequest represents request of StatPersistentPeer.
message StatPersistentPeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// DeletePersistentPeerRequest represents request of DeletePersistentPeer.
message DeletePersistentPeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// UploadPersistentTaskStartedRequest represents upload persistent task started request of UploadPersistentTaskStarted.
message UploadPersistentTaskStartedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
  // This is the key of the object storage where the persistent task will be stored,
  // for example: `file.txt` or `dir/file.txt`. The combination of object_storage_key,
  // object_storage.endpoint and object_storage.region must be unique, because
  // the persistent task cannot be overwritten once it is uploaded.
  string object_storage_key = 4 [(validate.rules).string.min_len = 1];
    // Object storage protocol information.
  common.v2.ObjectStorage object_storage = 5 [(validate.rules).message.required = true];
  // Replica count of the persistent task.
  uint64 persistent_replica_count = 6 [(validate.rules).uint64.gte = 1];
  // Tag is used to distinguish different persistent tasks.
  optional string tag = 7;
  // Application of task.
  optional string application = 8;
  // Task piece length, the value needs to be greater than or equal to 4194304(4MiB).
  uint64 piece_length = 9 [(validate.rules).uint64.gte = 4194304];
  // Task content length.
  uint64 content_length = 10;
  // Task piece count.
  uint32 piece_count = 11;
  // TTL of the persistent task.
  google.protobuf.Duration ttl = 12 [(validate.rules).duration = {gte:{seconds: 300}, lte:{seconds: 604800}}];
}

// UploadPersistentTaskFinishedRequest represents upload persistent task finished request of UploadPersistentTaskFinished.
message UploadPersistentTaskFinishedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// UploadPersistentTaskFailedRequest represents upload persistent task failed request of UploadPersistentTaskFailed.
message UploadPersistentTaskFailedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
  // The description of the upload failed.
  optional string description = 4 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// StatPersistentTaskRequest represents request of StatPersistentTask.
message StatPersistentTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// DeletePersistentTaskRequest represents request of DeletePersistentTask.
message DeletePersistentTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// RegisterPersistentCachePeerRequest represents persistent cache peer registered request of AnnouncePersistentCachePeerRequest.
message RegisterPersistentCachePeerRequest {
  // Persistent represents whether the persistent cache task is persistent.
  // If the persistent cache task is persistent, the persistent cache peer will
  // not be deleted when dfdaemon runs garbage collection.
  bool persistent = 1;
  // Tag is used to distinguish different persistent cache tasks.
  optional string tag = 2;
  // Application of task.
  optional string application = 3;
  // Task piece length, the value needs to be greater than or equal to 4194304(4MiB)
  uint64 piece_length = 4 [(validate.rules).uint64.gte = 4194304];
  // File path to be exported.
  optional string output_path = 5 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
  // Download timeout.
  optional google.protobuf.Duration timeout = 6;
  // concurrent_piece_count is the number of pieces that can be downloaded concurrently.
  optional uint32 concurrent_piece_count = 7;
  // Task piece count.
  uint64 piece_count = 8;
}

// DownloadPersistentCachePeerStartedRequest represents persistent cache peer download started request of AnnouncePersistentCachePeerRequest.
message DownloadPersistentCachePeerStartedRequest {
}

// ReschedulePersistentCachePeerRequest represents reschedule request of AnnouncePersistentCachePeerRequest.
message ReschedulePersistentCachePeerRequest {
  // Candidate parent ids.
  repeated common.v2.PersistentCachePeer candidate_parents = 1;

  // The description of the reschedule reason.
  optional string description = 2 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// DownloadPersistentCachePeerFinishedRequest represents persistent cache peer download finished request of AnnouncePersistentCachePeerRequest.
message DownloadPersistentCachePeerFinishedRequest {
  reserved 1;
  reserved "piece_count";
}

// DownloadPersistentCachePeerFailedRequest represents persistent cache peer download failed request of AnnouncePersistentCachePeerRequest.
message DownloadPersistentCachePeerFailedRequest {
  // The description of the download failed.
  optional string description = 1 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// AnnouncePersistentCachePeerRequest represents request of AnnouncePersistentCachePeer.
message AnnouncePersistentCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];

  oneof request {
    option (validate.required) = true;

    RegisterPersistentCachePeerRequest register_persistent_cache_peer_request = 4;
    DownloadPersistentCachePeerStartedRequest download_persistent_cache_peer_started_request = 5;
    ReschedulePersistentCachePeerRequest reschedule_persistent_cache_peer_request = 6;
    DownloadPersistentCachePeerFinishedRequest download_persistent_cache_peer_finished_request = 7;
    DownloadPersistentCachePeerFailedRequest download_persistent_cache_peer_failed_request = 8;
    DownloadPieceFinishedRequest download_piece_finished_request = 9;
    DownloadPieceFailedRequest download_piece_failed_request = 10;
  }
}

// EmptyPersistentCacheTaskResponse represents empty persistent cache task response of AnnouncePersistentCachePeerResponse.
message EmptyPersistentCacheTaskResponse {
}

// NormalPersistentCacheTaskResponse represents normal persistent cache task response of AnnouncePersistentCachePeerResponse.
message NormalPersistentCacheTaskResponse {
  // Candidate parents.
  repeated common.v2.PersistentCachePeer candidate_parents = 1 [(validate.rules).repeated.min_items = 1];
}

// AnnouncePersistentCachePeerResponse represents response of AnnouncePersistentCachePeer.
message AnnouncePersistentCachePeerResponse {
  oneof response {
    option (validate.required) = true;

    EmptyPersistentCacheTaskResponse empty_persistent_cache_task_response = 1;
    NormalPersistentCacheTaskResponse normal_persistent_cache_task_response = 2;
  }
}

// StatPersistentCachePeerRequest represents request of StatPersistentCachePeer.
message StatPersistentCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// DeletePersistentCachePeerRequest represents request of DeletePersistentCachePeer.
message DeletePersistentCachePeerRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// UploadPersistentCacheTaskStartedRequest represents upload persistent cache task started request of UploadPersistentCacheTaskStartedRequest.
message UploadPersistentCacheTaskStartedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
  // Replica count of the persistent cache task.
  uint64 persistent_replica_count = 4 [(validate.rules).uint64.gte = 1];
  // Tag is used to distinguish different persistent cache tasks.
  optional string tag = 5;
  // Application of task.
  optional string application = 6;
  // Task piece length, the value needs to be greater than or equal to 4194304(4MiB)
  uint64 piece_length = 7 [(validate.rules).uint64.gte = 4194304];
  // Task content length.
  uint64 content_length = 8;
  // Task piece count.
  uint32 piece_count = 9;
  // TTL of the persistent cache task.
  google.protobuf.Duration ttl = 10 [(validate.rules).duration = {gte:{seconds: 300}, lte:{seconds: 604800}}];
}

// UploadPersistentCacheTaskFinishedRequest represents upload persistent cache task finished request of UploadPersistentCacheTaskFinishedRequest.
message UploadPersistentCacheTaskFinishedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
}

// UploadPersistentCacheTaskFailedRequest represents upload persistent cache task failed request of UploadPersistentCacheTaskFailedRequest.
message UploadPersistentCacheTaskFailedRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
  // Peer id.
  string peer_id = 3 [(validate.rules).string.min_len = 1];
  // The description of the upload failed.
  optional string description = 4 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// StatPersistentCacheTaskRequest represents request of StatPersistentCacheTask.
message StatPersistentCacheTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// DeletePersistentCacheTaskRequest represents request of DeletePersistentCacheTask.
message DeletePersistentCacheTaskRequest {
  // Host id.
  string host_id = 1 [(validate.rules).string.min_len = 1];
  // Task id.
  string task_id = 2 [(validate.rules).string.min_len = 1];
}

// PreheatImageRequest represents request of PreheatImage.
message PreheatImageRequest {
  // URL is the image manifest url for preheating.
  string url = 1 [(validate.rules).string.uri = true];
	// Piece Length is the piece length(bytes) for downloading file. The value needs to
	// be greater than 4MiB (4,194,304 bytes) and less than 64MiB (67,108,864 bytes),
	// for example: 4194304(4mib), 8388608(8mib). If the piece length is not specified,
	// the piece length will be calculated according to the file size.
  optional uint64 piece_length = 2 [(validate.rules).uint64 = {gte: 4194304, lte: 67108864, ignore_empty: true}];
	// Tag is the tag for preheating.
  optional string tag = 3;
	// Application is the application string for preheating.
  optional string application = 4;
  // Filtered query params to generate the task id.
  // When filter is ["Signature", "Expires", "ns"], for example:
  // http://example.com/xyz?Expires=e1&Signature=s1&ns=docker.io and http://example.com/xyz?Expires=e2&Signature=s2&ns=docker.io
  // will generate the same task id.
  // Default value includes the filtered query params of s3, gcs, oss, obs, cos.
  repeated string filtered_query_params = 5;
	// Header is the http headers for authentication.
  map<string, string> header = 6;
	// Username is the username for authentication.
  optional string username = 7;
	// Password is the password for authentication.
  optional string password = 8;
  // Platform is the platform for preheating, such as linux/amd64, linux/arm64, etc.
  optional string platform = 9;
  // Scope is the scope for preheating, it can be one of the following values:
  // - single_seed_peer: preheat from a single seed peer.
  // - all_seed_peers: preheat from all seed peers.
  // - all_peers: preheat from all available peers.
  string scope = 10 [(validate.rules).string.pattern = "^(single_seed_peer|all_seed_peers|all_peers)$"];
	// IPs is a list of specific peer IPs for preheating.
	// This field has the highest priority: if provided, both 'Count' and 'Percentage' will be ignored.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  repeated string ips = 11;
	// Percentage is the percentage of available peers to preheat.
	// This field has the lowest priority and is only used if both 'IPs' and 'Count' are not provided.
	// It must be a value between 1 and 100 (inclusive) if provided.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  optional uint32 percentage = 12 [(validate.rules).uint32 = {gte: 1, lte: 100, ignore_empty: true}];
	// Count is the desired number of peers to preheat.
	// This field is used only when 'IPs' is not specified. It has priority over 'Percentage'.
	// It must be a value between 1 and 200 (inclusive) if provided.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  optional uint32 count = 13 [(validate.rules).uint32 = {gte: 1, lte: 200, ignore_empty: true}];
	// ConcurrentTaskCount specifies the maximum number of tasks (e.g., image layers) to preheat concurrently.
	// For example, if preheating 100 layers with ConcurrentTaskCount set to 10, up to 10 layers are processed simultaneously.
	// If ConcurrentPeerCount is 10 for 1000 peers, each layer is preheated by 10 peers concurrently.
	// Default is 8, maximum is 100.
  optional int64 concurrent_task_count = 14 [(validate.rules).int64 = {gte: 1, lte: 100, ignore_empty: true}];
	// ConcurrentPeerCount specifies the maximum number of peers to preheat concurrently for a single task (e.g., an image layer).
	// For example, if preheating a layer with ConcurrentPeerCount set to 10, up to 10 peers process that layer simultaneously.
	// Default is 500, maximum is 1000.
  optional int64 concurrent_peer_count = 15 [(validate.rules).int64 = {gte: 1, lte: 1000, ignore_empty: true}];
	// Timeout is the timeout for preheating, default is 30 minutes.
  optional google.protobuf.Duration timeout = 16;
  // Preheat priority.
  common.v2.Priority priority = 17 [(validate.rules).enum.defined_only = true];
  // certificate_chain is the client certs with DER format for the backend client.
  repeated bytes certificate_chain = 18;
  // insecure_skip_verify indicates whether to skip TLS verification.
  bool insecure_skip_verify = 19;
}

// StatImageRequest represents request of StatImage.
message StatImageRequest {
  // URL is the image manifest url for preheating.
  string url = 1 [(validate.rules).string.uri = true];
	// Piece Length is the piece length(bytes) for downloading file. The value needs to
	// be greater than 4MiB (4,194,304 bytes) and less than 64MiB (67,108,864 bytes),
	// for example: 4194304(4mib), 8388608(8mib). If the piece length is not specified,
	// the piece length will be calculated according to the file size.
  optional uint64 piece_length = 2 [(validate.rules).uint64 = {gte: 4194304, lte: 67108864, ignore_empty: true}];
	// Tag is the tag for preheating.
  optional string tag = 3;
	// Application is the application string for preheating.
  optional string application = 4;
  // Filtered query params to generate the task id.
  // When filter is ["Signature", "Expires", "ns"], for example:
  // http://example.com/xyz?Expires=e1&Signature=s1&ns=docker.io and http://example.com/xyz?Expires=e2&Signature=s2&ns=docker.io
  // will generate the same task id.
  // Default value includes the filtered query params of s3, gcs, oss, obs, cos.
  repeated string filtered_query_params = 5;
	// Header is the http headers for authentication.
  map<string, string> header = 6;
	// Username is the username for authentication.
  optional string username = 7;
	// Password is the password for authentication.
  optional string password = 8;
  // Platform is the platform for preheating, such as linux/amd64, linux/arm64, etc.
  optional string platform = 9;
	// ConcurrentLayerCount specifies the maximum number of layers to get concurrently.
	// For example, if stat 100 layers with ConcurrentLayerCount set to 10, up to 10 layers are processed simultaneously.
	// If ConcurrentPeerCount is 10 for 1000 peers, each layer is stated by 10 peers concurrently.
	// Default is 8, maximum is 100.
  optional int64 concurrent_layer_count = 10 [(validate.rules).int64 = {gte: 1, lte: 100, ignore_empty: true}];
	// ConcurrentPeerCount specifies the maximum number of peers stat concurrently for a single task (e.g., an image layer).
	// For example, if stat a layer with ConcurrentPeerCount set to 10, up to 10 peers process that layer simultaneously.
	// Default is 500, maximum is 1000.
  optional int64 concurrent_peer_count = 11 [(validate.rules).int64 = {gte: 1, lte: 1000, ignore_empty: true}];
	// Timeout is the timeout for preheating, default is 30 minutes.
  optional google.protobuf.Duration timeout = 12;
  // certificate_chain is the client certs with DER format for the backend client.
  repeated bytes certificate_chain = 13;
  // insecure_skip_verify indicates whether to skip TLS verification.
  bool insecure_skip_verify = 14;
}

// StatImageResponse represents response of StatImage.
message StatImageResponse {
	// Image is the image information.
	Image image = 1;
	// Peers is the peers that have downloaded the image.
	repeated PeerImage peers = 2;
}

// PeerImage represents a peer in the get image job.
message PeerImage {
	// IP is the IP address of the peer.
  string ip = 1 [(validate.rules).string.ip = true];
	// Hostname is the hostname of the peer.
  string hostname = 2 [(validate.rules).string.min_len = 1];
	// CachedLayers is the list of layers that the peer has downloaded.
  repeated Layer cached_layers = 3;
}

// Image represents the image information.
message Image {
  // Layers is the list of layers of the image.
  repeated Layer layers = 1;
}

// Layer represents a layer of the image.
message Layer {
	// URL is the URL of the layer.
  string url = 1 [(validate.rules).string.uri = true];
  // IsFinished indicates whether the layer has finished downloading on the peer.
  optional bool is_finished = 2;
}

// PreheatFileRequest represents request of PreheatFile.
message PreheatFileRequest {
  // URL is the file url for preheating.
  string url = 1 [(validate.rules).string.uri = true];
	// Piece Length is the piece length(bytes) for downloading file. The value needs to
	// be greater than 4MiB (4,194,304 bytes) and less than 64MiB (67,108,864 bytes),
	// for example: 4194304(4mib), 8388608(8mib). If the piece length is not specified,
	// the piece length will be calculated according to the file size.
  optional uint64 piece_length = 2 [(validate.rules).uint64 = {gte: 4194304, lte: 67108864, ignore_empty: true}];
	// Tag is the tag for preheating.
  optional string tag = 3;
	// Application is the application string for preheating.
  optional string application = 4;
  // Filtered query params to generate the task id.
  // When filter is ["Signature", "Expires", "ns"], for example:
  // http://example.com/xyz?Expires=e1&Signature=s1&ns=docker.io and http://example.com/xyz?Expires=e2&Signature=s2&ns=docker.io
  // will generate the same task id.
  // Default value includes the filtered query params of s3, gcs, oss, obs, cos.
  repeated string filtered_query_params = 5;
	// Header is the http headers for authentication.
  map<string, string> header = 6;
  // Scope is the scope for preheating, it can be one of the following values:
  // - single_seed_peer: preheat from a single seed peer.
  // - all_peers: preheat from all available peers.
  // - all_seed_peers: preheat from all seed peers.
  string scope = 7 [(validate.rules).string.pattern = "^(single_seed_peer|all_seed_peers|all_peers)$"];
	// IPs is a list of specific peer IPs for preheating.
	// This field has the highest priority: if provided, both 'Count' and 'Percentage' will be ignored.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  repeated string ips = 8;
	// Percentage is the percentage of available peers to preheat.
	// This field has the lowest priority and is only used if both 'IPs' and 'Count' are not provided.
	// It must be a value between 1 and 100 (inclusive) if provided.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  optional uint32 percentage = 9 [(validate.rules).uint32 = {gte: 1, lte: 100, ignore_empty: true}];
	// Count is the desired number of peers to preheat.
	// This field is used only when 'IPs' is not specified. It has priority over 'Percentage'.
	// It must be a value between 1 and 200 (inclusive) if provided.
	// Applies to 'all_peers' and 'all_seed_peers' scopes.
  optional uint32 count = 10 [(validate.rules).uint32 = {gte: 1, lte: 200, ignore_empty: true}];
	// ConcurrentTaskCount specifies the maximum number of tasks to preheat concurrently.
	// For example, if preheating 100 files with ConcurrentTaskCount set to 10, up to 10 files are processed simultaneously.
	// If ConcurrentPeerCount is 10 for 1000 peers, each file is preheated by 10 peers concurrently.
	// Default is 8, maximum is 100.
  optional int64 concurrent_task_count = 11 [(validate.rules).int64 = {gte: 1, lte: 100, ignore_empty: true}];
	// ConcurrentPeerCount specifies the maximum number of peers to preheat concurrently for a single task.
	// For example, if preheating a file with ConcurrentPeerCount set to 10, up to 10 peers process that file simultaneously.
	// Default is 500, maximum is 1000.
  optional int64 concurrent_peer_count = 12 [(validate.rules).int64 = {gte: 1, lte: 1000, ignore_empty: true}];
	// Timeout is the timeout for preheating, default is 30 minutes.
  optional google.protobuf.Duration timeout = 13;
  // Preheat priority.
  common.v2.Priority priority = 14 [(validate.rules).enum.defined_only = true];
  // certificate_chain is the client certs with DER format for the backend client.
  repeated bytes certificate_chain = 15;
  // insecure_skip_verify indicates whether to skip TLS verification.
  bool insecure_skip_verify = 16;
  // Object storage protocol information.
  optional common.v2.ObjectStorage object_storage = 17;
  // HDFS protocol information.
  optional common.v2.HDFS hdfs = 18;
  // output_path is the path to preheat the file or directory to destination.
  optional string output_path = 19 [(validate.rules).string = {min_len: 1, ignore_empty: true}];
}

// StatFileRequest represents request of StatFile.
message StatFileRequest {
  // URL is the file url for stat.
  string url = 1 [(validate.rules).string.uri = true];
	// Piece Length is the piece length(bytes) for downloading file. The value needs to
	// be greater than 4MiB (4,194,304 bytes) and less than 64MiB (67,108,864 bytes),
	// for example: 4194304(4mib), 8388608(8mib). If the piece length is not specified,
	// the piece length will be calculated according to the file size.
  optional uint64 piece_length = 2 [(validate.rules).uint64 = {gte: 4194304, lte: 67108864, ignore_empty: true}];
	// Tag is the tag for stat.
  optional string tag = 3;
	// Application is the application string for stat.
  optional string application = 4;
  // Filtered query params to generate the task id.
  // When filter is ["Signature", "Expires", "ns"], for example:
  // http://example.com/xyz?Expires=e1&Signature=s1&ns=docker.io and http://example.com/xyz?Expires=e2&Signature=s2&ns=docker.io
  // will generate the same task id.
  // Default value includes the filtered query params of s3, gcs, oss, obs, cos.
  repeated string filtered_query_params = 5;
	// Header is the http headers for authentication.
  map<string, string> header = 6;
	// ConcurrentPeerCount specifies the maximum number of peers stat concurrently for a single task.
	// For example, if stat a file with ConcurrentPeerCount set to 10, up to 10 peers process that file simultaneously.
	// Default is 500, maximum is 1000.
  optional int64 concurrent_peer_count = 7 [(validate.rules).int64 = {gte: 1, lte: 1000, ignore_empty: true}];
	// Timeout is the timeout for stat, default is 30 minutes.
  optional google.protobuf.Duration timeout = 8;
  // certificate_chain is the client certs with DER format for the backend client.
  repeated bytes certificate_chain = 9;
  // insecure_skip_verify indicates whether to skip TLS verification.
  bool insecure_skip_verify = 10;
  // Object storage protocol information.
  optional common.v2.ObjectStorage object_storage = 11;
  // HDFS protocol information.
  optional common.v2.HDFS hdfs = 12;
}

// StatFileResponse represents response of StatFile.
message StatFileResponse {
	// Peers is the peers that have downloaded the file.
	repeated PeerFile peers = 1;
}

// PeerFile represents a peer in the get file job.
message PeerFile {
	// IP is the IP address of the peer.
  string ip = 1;
	// Hostname is the hostname of the peer.
  string hostname = 2;
  // CachedFiles is the list of files that the peer has downloaded.
  repeated File cached_files = 3;
}

// File represents the file information.
message File { 
  // URL is the url of the file.
  string url = 1 [(validate.rules).string.uri = true];
  // IsFinished indicates whether the file has finished downloading on the peer.
  optional bool is_finished = 2;
}


// Scheduler RPC Service.
service Scheduler {
  // AnnouncePeer announces peer to scheduler.
  rpc AnnouncePeer(stream AnnouncePeerRequest) returns(stream AnnouncePeerResponse);

  // Checks information of peer.
  rpc StatPeer(StatPeerRequest)returns(common.v2.Peer);

  // DeletePeer releases peer in scheduler.
  rpc DeletePeer(DeletePeerRequest)returns(google.protobuf.Empty);

  // Checks information of task.
  rpc StatTask(StatTaskRequest)returns(common.v2.Task);

  // DeleteTask releases task in scheduler.
  rpc DeleteTask(DeleteTaskRequest)returns(google.protobuf.Empty);

  // AnnounceHost announces host to scheduler.
  rpc AnnounceHost(AnnounceHostRequest)returns(google.protobuf.Empty);

  // ListHosts lists hosts in scheduler.
  rpc ListHosts(ListHostsRequest)returns(ListHostsResponse);

  // DeleteHost releases host in scheduler.
  rpc DeleteHost(DeleteHostRequest)returns(google.protobuf.Empty);

  // AnnounceCachePeer announces cache peer to scheduler.
  rpc AnnounceCachePeer(stream AnnounceCachePeerRequest) returns(stream AnnounceCachePeerResponse);

  // Checks information of cache peer.
  rpc StatCachePeer(StatCachePeerRequest)returns(common.v2.CachePeer);

  // DeleteCachePeer releases cache peer in scheduler.
  rpc DeleteCachePeer(DeleteCachePeerRequest)returns(google.protobuf.Empty);

  // Checks information of cache task.
  rpc StatCacheTask(StatCacheTaskRequest)returns(common.v2.CacheTask);

  // DeleteCacheTask releases cache task in scheduler.
  rpc DeleteCacheTask(DeleteCacheTaskRequest)returns(google.protobuf.Empty);

  // AnnouncePersistentPeer announces persistent peer to scheduler.
  rpc AnnouncePersistentPeer(stream AnnouncePersistentPeerRequest) returns(stream AnnouncePersistentPeerResponse);

  // Checks information of persistent peer.
  rpc StatPersistentPeer(StatPersistentPeerRequest)returns(common.v2.PersistentPeer);

  // DeletePersistentPeer releases persistent peer in scheduler.
  rpc DeletePersistentPeer(DeletePersistentPeerRequest)returns(google.protobuf.Empty);

  // UploadPersistentTaskStarted uploads persistent task started to scheduler.
  rpc UploadPersistentTaskStarted(UploadPersistentTaskStartedRequest)returns(google.protobuf.Empty);

  // UploadPersistentTaskFinished uploads persistent task finished to scheduler.
  rpc UploadPersistentTaskFinished(UploadPersistentTaskFinishedRequest)returns(common.v2.PersistentTask);

  // UploadPersistentTaskFailed uploads persistent task failed to scheduler.
  rpc UploadPersistentTaskFailed(UploadPersistentTaskFailedRequest)returns(google.protobuf.Empty);

  // Checks information of persistent task.
  rpc StatPersistentTask(StatPersistentTaskRequest)returns(common.v2.PersistentTask);

  // DeletePersistentTask releases persistent task in scheduler.
  rpc DeletePersistentTask(DeletePersistentTaskRequest)returns(google.protobuf.Empty);

  // AnnouncePersistentCachePeer announces persistent cache peer to scheduler.
  rpc AnnouncePersistentCachePeer(stream AnnouncePersistentCachePeerRequest) returns(stream AnnouncePersistentCachePeerResponse);

  // Checks information of persistent cache peer.
  rpc StatPersistentCachePeer(StatPersistentCachePeerRequest)returns(common.v2.PersistentCachePeer);

  // DeletePersistentCachePeer releases persistent cache peer in scheduler.
  rpc DeletePersistentCachePeer(DeletePersistentCachePeerRequest)returns(google.protobuf.Empty);

  // UploadPersistentCacheTaskStarted uploads persistent cache task started to scheduler.
  rpc UploadPersistentCacheTaskStarted(UploadPersistentCacheTaskStartedRequest)returns(google.protobuf.Empty);

  // UploadPersistentCacheTaskFinished uploads persistent cache task finished to scheduler.
  rpc UploadPersistentCacheTaskFinished(UploadPersistentCacheTaskFinishedRequest)returns(common.v2.PersistentCacheTask);

  // UploadPersistentCacheTaskFailed uploads persistent cache task failed to scheduler.
  rpc UploadPersistentCacheTaskFailed(UploadPersistentCacheTaskFailedRequest)returns(google.protobuf.Empty);

  // Checks information of persistent cache task.
  rpc StatPersistentCacheTask(StatPersistentCacheTaskRequest)returns(common.v2.PersistentCacheTask);

  // DeletePersistentCacheTask releases persistent cache task in scheduler.
  rpc DeletePersistentCacheTask(DeletePersistentCacheTaskRequest)returns(google.protobuf.Empty);

  // PreheatImage synchronously resolves an image manifest and triggers an asynchronous preheat task.
  //
  // This is a blocking call. The RPC will not return until the server has completed the
  // initial synchronous work: resolving the image manifest and preparing all layer URLs.
  //
  // After this call successfully returns, a scheduler on the server begins the actual
  // preheating process, instructing peers to download the layers in the background.
  //
  // A successful response (google.protobuf.Empty) confirms that the preparation is complete
  // and the asynchronous download task has been scheduled.
  rpc PreheatImage(PreheatImageRequest)returns(google.protobuf.Empty);

  // StatImage provides detailed status for a container image's distribution in peers.
  //
  // This is a blocking call that first resolves the image manifest and then queries
  // all peers to collect the image's download state across the network.
  // The response includes both layer information and the status on each peer.
  rpc StatImage(StatImageRequest)returns(StatImageResponse);
  
  // PreheatFile synchronously resolves a file URL and triggers an asynchronous preheat task.
  //
  // This is a blocking call. The RPC will not return until the server has completed the
  // initial synchronous work: resolving the file URL.
  //
  // After this call successfully returns, a scheduler on the server begins the actual
  // preheating process, instructing peers to download the file in the background.
  //
  // A successful response (google.protobuf.Empty) confirms that the preparation is complete
  // and the asynchronous download task has been scheduled.
  rpc PreheatFile(PreheatFileRequest)returns(google.protobuf.Empty);

  // StatFile provides detailed status for a file's distribution in peers.
  //
  // This is a blocking call that first resolves the file URL and then queries
  // all peers to collect the file's download state across the network.
  // The response includes both file information and the status on each peer.
  rpc StatFile(StatFileRequest)returns(StatFileResponse);
}
