syntax = "proto3";

package whpb;

import "metapb.proto";

import "gogoproto/gogo.proto";

option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
option (gogoproto.unmarshaler_all) = true;

// Interfaces exported by ether-client server.
service Ether {
    // WorkerHeartbeat represents heartbeat interface interacted with ether-client server.
    rpc WorkerHeartbeat(stream WorkerHeartbeatRequest) returns (stream WorkerHeartbeatResponse) {}
    // RegisterWorker registers worker
    rpc RegisterWorker(RegisterWorkerRequest) returns (RegisterWorkerResponse) {}
    // RenewJob renews job lease.
    // if we fail to renew job in lease, we should give up this job.
    rpc RenewJob(RenewJobRequest) returns (RenewJobResponse) {}
    // GetClusterInfo returns cluster info.
    rpc GetClusterInfo(GetClusterInfoRequest) returns (GetClusterInfoResponse) {}
    // CreateFence creates fence under one topic.
    rpc CreateFence(CreateFenceRequest) returns (CreateFenceResponse) {}
    // WaitOnFence waits on it's fences util all consumers reach all fences.
    rpc WaitOnFenceMidway(WaitOnFenceRequest) returns (stream WaitOnFenceResponse) {}
    rpc WaitOnFenceFinal(WaitOnFenceRequest) returns (stream WaitOnFenceResponse) {}
}

enum ErrorCode {
    NotBootStrapped     = 0;
    NotLeader           = 1;
    ContractExipred     = 2;
    RenewContract       = 3;
    CreateNewWorker     = 4;
    CreateNewFence      = 5;
    Unknown             = 6;
}

message Error {
    ErrorCode errcode = 1;
    string    message = 2;
}

message RequestHeader {
    uint64 cluster_id   = 1;
    uint64 worker_id    = 2;
}

message ResponseHeader {
    uint64 cluster_id   = 1;
    uint64 worker_id    = 2;
    Error error         = 3;
}

message WorkerHeartbeatRequest {
    RequestHeader header            = 1;

    // worker should report all jobs that it works on.
    repeated JobStatus jobs  = 2;
}

message WorkerHeartbeatResponse {
    ResponseHeader header            = 1;

    // new jobs that ether-client assigns to worker.
    repeated Job new_jobs     = 2;

    // obsolete jobs that worker would give up.
    repeated uint64 obsolete_job_ids = 3;
}

message RegisterWorkerRequest {
    RequestHeader header            = 1;
    Worker worker            = 2;
}

message RegisterWorkerResponse {
    ResponseHeader header           = 1;
}

message RenewJobRequest {
     RequestHeader header           = 1;
     repeated uint64 job_ids        = 2;
     int64  lease                   = 3;
}

message RenewJobResponse {
    ResponseHeader header           = 1;
    repeated uint64 expiredJobs     = 2;
    repeated uint64 errorJobs       = 3;
}

message GetClusterInfoRequest {
}

message GetClusterInfoResponse {
    uint64 cluster_id           = 1;
    // key prefix in storage.
    string storage_root_path    = 2;
    Member leader               = 3;
    repeated Member members     = 4;
}

message CreateFenceRequest {
    RequestHeader header    = 1;
    repeated Topic topics    = 2;
}

message CreateFenceResponse {
    ResponseHeader  header  = 1;
    uint64 fence_id         = 2;
}

message WaitOnFenceRequest {
    RequestHeader header      = 1;
    uint64 fence_id           = 2;
    uint64 job_id             = 3;
    Topic  topic              = 4;
    repeated int32 partitions = 5;
}

message WaitOnFenceResponse {
    ResponseHeader header   = 1;
    bool isSynced           = 2;
}

message Member {
    // name is the name of the ether-client member.
    string name                 = 1;
    // member_id is the unique id of the ether-client member.
    uint64 member_id            = 2;
    repeated string peer_urls   = 3;
    repeated string client_urls = 4;
}