syntax = "proto3";

package chainfire.v1;

// Key-Value service
service KV {
    // Range gets the keys in the range from the key-value store
    rpc Range(RangeRequest) returns (RangeResponse);

    // Put puts the given key into the key-value store
    rpc Put(PutRequest) returns (PutResponse);

    // Delete deletes the given range from the key-value store
    rpc Delete(DeleteRangeRequest) returns (DeleteRangeResponse);

    // Txn processes multiple requests in a single transaction
    rpc Txn(TxnRequest) returns (TxnResponse);
}

// Watch service
service Watch {
    // Watch watches for events happening or that have happened
    rpc Watch(stream WatchRequest) returns (stream WatchResponse);
}

// Cluster management service
service Cluster {
    // MemberAdd adds a member into the cluster
    rpc MemberAdd(MemberAddRequest) returns (MemberAddResponse);

    // MemberRemove removes an existing member from the cluster
    rpc MemberRemove(MemberRemoveRequest) returns (MemberRemoveResponse);

    // MemberList lists all the members in the cluster
    rpc MemberList(MemberListRequest) returns (MemberListResponse);

    // Status gets the status of the cluster
    rpc Status(StatusRequest) returns (StatusResponse);
}

// Response header included in all responses
message ResponseHeader {
    // cluster_id is the ID of the cluster
    uint64 cluster_id = 1;
    // member_id is the ID of the responding member
    uint64 member_id = 2;
    // revision is the key-value store revision
    int64 revision = 3;
    // raft_term is the current Raft term
    uint64 raft_term = 4;
}

// Key-value pair
message KeyValue {
    // key is the key in bytes
    bytes key = 1;
    // create_revision is the revision of last creation
    int64 create_revision = 2;
    // mod_revision is the revision of last modification
    int64 mod_revision = 3;
    // version is the version of the key
    int64 version = 4;
    // value is the value held by the key
    bytes value = 5;
    // lease is the ID of the lease attached to the key
    int64 lease = 6;
}

// ========== Range ==========

message RangeRequest {
    // key is the first key for the range
    bytes key = 1;
    // range_end is the upper bound on the requested range
    bytes range_end = 2;
    // limit is a limit on the number of keys returned
    int64 limit = 3;
    // revision is the point-in-time of the store to use
    int64 revision = 4;
    // keys_only when set returns only the keys and not the values
    bool keys_only = 5;
    // count_only when set returns only the count of the keys
    bool count_only = 6;
}

message RangeResponse {
    ResponseHeader header = 1;
    // kvs is the list of key-value pairs matched by the range request
    repeated KeyValue kvs = 2;
    // more indicates if there are more keys to return
    bool more = 3;
    // count is set to the number of keys within the range
    int64 count = 4;
}

// ========== Put ==========

message PutRequest {
    // key is the key to put
    bytes key = 1;
    // value is the value to put
    bytes value = 2;
    // lease is the lease ID to attach to the key
    int64 lease = 3;
    // prev_kv when set returns the previous key-value pair
    bool prev_kv = 4;
}

message PutResponse {
    ResponseHeader header = 1;
    // prev_kv is the key-value pair before the put
    KeyValue prev_kv = 2;
}

// ========== Delete ==========

message DeleteRangeRequest {
    // key is the first key to delete
    bytes key = 1;
    // range_end is the key following the last key to delete
    bytes range_end = 2;
    // prev_kv when set returns deleted key-value pairs
    bool prev_kv = 3;
}

message DeleteRangeResponse {
    ResponseHeader header = 1;
    // deleted is the number of keys deleted
    int64 deleted = 2;
    // prev_kvs holds the deleted key-value pairs
    repeated KeyValue prev_kvs = 3;
}

// ========== Transaction ==========

message TxnRequest {
    // compare is a list of predicates
    repeated Compare compare = 1;
    // success is a list of operations to apply if all comparisons succeed
    repeated RequestOp success = 2;
    // failure is a list of operations to apply if any comparison fails
    repeated RequestOp failure = 3;
}

message TxnResponse {
    ResponseHeader header = 1;
    // succeeded is set to true if all comparisons evaluated to true
    bool succeeded = 2;
    // responses is a list of responses corresponding to the results
    repeated ResponseOp responses = 3;
}

message Compare {
    enum CompareResult {
        EQUAL = 0;
        GREATER = 1;
        LESS = 2;
        NOT_EQUAL = 3;
    }
    enum CompareTarget {
        VERSION = 0;
        CREATE = 1;
        MOD = 2;
        VALUE = 3;
    }
    CompareResult result = 1;
    CompareTarget target = 2;
    bytes key = 3;
    oneof target_union {
        int64 version = 4;
        int64 create_revision = 5;
        int64 mod_revision = 6;
        bytes value = 7;
    }
}

message RequestOp {
    oneof request {
        RangeRequest request_range = 1;
        PutRequest request_put = 2;
        DeleteRangeRequest request_delete_range = 3;
    }
}

message ResponseOp {
    oneof response {
        RangeResponse response_range = 1;
        PutResponse response_put = 2;
        DeleteRangeResponse response_delete_range = 3;
    }
}

// ========== Watch ==========

message WatchRequest {
    oneof request_union {
        WatchCreateRequest create_request = 1;
        WatchCancelRequest cancel_request = 2;
        WatchProgressRequest progress_request = 3;
    }
}

message WatchCreateRequest {
    // key is the key to watch
    bytes key = 1;
    // range_end is the end of the range to watch
    bytes range_end = 2;
    // start_revision is an optional revision to start watching from
    int64 start_revision = 3;
    // progress_notify is set to true to enable progress notifications
    bool progress_notify = 4;
    // prev_kv when set includes previous key-value in events
    bool prev_kv = 5;
    // watch_id is the user-provided watch ID (0 for server-assigned)
    int64 watch_id = 6;
}

message WatchCancelRequest {
    // watch_id is the watch ID to cancel
    int64 watch_id = 1;
}

message WatchProgressRequest {}

message WatchResponse {
    ResponseHeader header = 1;
    // watch_id is the watch ID for this response
    int64 watch_id = 2;
    // created is set to true if this response is for a create request
    bool created = 3;
    // canceled is set to true if the watch was canceled
    bool canceled = 4;
    // compact_revision is the minimum revision the watcher may receive
    int64 compact_revision = 5;
    // cancel_reason indicates the reason for cancellation
    string cancel_reason = 6;
    // events is the list of events in this response
    repeated Event events = 11;
}

message Event {
    enum EventType {
        PUT = 0;
        DELETE = 1;
    }
    // type is the kind of event
    EventType type = 1;
    // kv is the KeyValue affected by the event
    KeyValue kv = 2;
    // prev_kv is the KeyValue prior to the event
    KeyValue prev_kv = 3;
}

// ========== Cluster Management ==========

message Member {
    // ID is the member ID
    uint64 id = 1;
    // name is the human-readable name
    string name = 2;
    // peer_urls are URLs for Raft communication
    repeated string peer_urls = 3;
    // client_urls are URLs for client communication
    repeated string client_urls = 4;
    // is_learner indicates if member is a learner
    bool is_learner = 5;
}

message MemberAddRequest {
    // peer_urls are the URLs to reach the new member
    repeated string peer_urls = 1;
    // is_learner indicates if the member is a learner
    bool is_learner = 2;
}

message MemberAddResponse {
    ResponseHeader header = 1;
    // member is the member information for the added member
    Member member = 2;
    // members is the list of all members after adding
    repeated Member members = 3;
}

message MemberRemoveRequest {
    // ID is the member ID to remove
    uint64 id = 1;
}

message MemberRemoveResponse {
    ResponseHeader header = 1;
    // members is the list of all members after removing
    repeated Member members = 2;
}

message MemberListRequest {}

message MemberListResponse {
    ResponseHeader header = 1;
    // members is the list of all members
    repeated Member members = 2;
}

message StatusRequest {}

message StatusResponse {
    ResponseHeader header = 1;
    // version is the version of the server
    string version = 2;
    // db_size is the size of the database
    int64 db_size = 3;
    // leader is the member ID of the current leader
    uint64 leader = 4;
    // raft_index is the current Raft committed index
    uint64 raft_index = 5;
    // raft_term is the current Raft term
    uint64 raft_term = 6;
    // raft_applied_index is the current Raft applied index
    uint64 raft_applied_index = 7;
}
