syntax="proto3";

import "minknow/rpc/acquisition.proto";
import "minknow/rpc/device.proto";
import "minknow/rpc/rpc_options.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

package ont.rpc.protocol;

service ProtocolService {
    // Initiates a python instance that runs the script specified by the `path` argument.
    // `list_protocols` will give back a list of protocol scripts that can be started by this call
    rpc start_protocol (StartProtocolRequest) returns (StartProtocolResponse) {}

    // Stops the currently running protocol script instance.
    rpc stop_protocol (StopProtocolRequest) returns (StopProtocolResponse) {}

    // Wait for a protocol run to finish.
    //
    // The call blocks until the run with the given run ID has finished (or returns immediately if
    // it had already finished) and returns information about the protocol run.
    //
    // If no run has been started with the provided run ID (or no run ID is given), an error is
    // returned.
    //
    // If NOTIFY_BEFORE_TERMINATION is specified for state, the protocol end time is an estimate, including
    // the allowed timeout.
    //
    // Since 1.10
    rpc wait_for_finished (WaitForFinishedRequest) returns (ProtocolRunInfo) {}

    // Gets information about a protocol run.
    //
    // If no run ID is provided, information about the most recently started protocol run is
    // provided.
    //
    // Since 1.10
    rpc get_run_info (GetRunInfoRequest) returns (ProtocolRunInfo) {}

    // List previously started protocol run ids (including any current protocol), in order of starting.
    //
    // The returned object can be used to find protocol information with get_run_info.
    //
    // Since 1.11
    rpc list_protocol_runs (ListProtocolRunsRequest) returns (ListProtocolRunsResponse) {}

    // Returns the name and run id of the currently running protocol.
    //
    // Will fail with FAILED_PRECONDITION if there is no protocol running
    //
    // Since 1.11
    rpc get_current_protocol_run (GetCurrentProtocolRunRequest) returns (ProtocolRunInfo) {}

    // Returns current protocol run info and streams any changes to the current protocol
    //
    // This call can be made even if there is no current protocol running. In this case, the next streamed
    // response will be the start of a new protocol instance and you will receive updates for that protocol
    // until it finishes
    //
    // If a protocol finishes this stream will still continue to run and you will be notified when a new protocol starts
    //
    // Since 1.12
    rpc watch_current_protocol_run (WatchCurrentProtocolRunRequest) returns (stream ProtocolRunInfo) {}

    // Gives back a list that contains info about each possible protocol script minknow is aware of.
    // This will most likely be used to retrieve a suitable protocol script that can be passed on to `start_protocol`
    //
    // Since 1.10
    rpc list_protocols (ListProtocolsRequest) returns (ListProtocolsResponse) {}

    // Returns string-to-string map of the context tags
    //
    // Since 1.11
    rpc get_context_info (GetContextInfoRequest) returns (GetContextInfoResponse) {}

    // Store context tags as arbitary string-to-string map
    //
    // Since 1.11
    rpc set_context_info (SetContextInfoRequest) returns (SetContextInfoResponse) {}

    // Sample id is a value set from the GUI that is defined by the user to identify an experiment.
    // This call gets this value
    // Deprecated: The sample_id is provided in the ProtocolRunUserInfo
    //
    // Since 1.11
    rpc get_sample_id (GetSampleIdRequest) returns (GetSampleIdResponse) {
        option deprecated = true;
    }

    // Sets the sample id. Refer to get_sample_id for what sample id is used for
    // Deprecated: The sample_id should be set in the request when a protocol starts ( start_protocol() )
    //
    // Since 1.11
    rpc set_sample_id (SetSampleIdRequest) returns (SetSampleIdResponse) {
        option deprecated = true;
    }

    // Value set by protocol scripts to define the purpose of the script. Gets this value
    //
    // Since 1.11
    rpc get_protocol_purpose (GetProtocolPurposeRequest) returns (GetProtocolPurposeResponse) {}

    // Sets the protocol purpose. See also get_protocol_purpose
    //
    // Since 1.11
    rpc set_protocol_purpose (SetProtocolPurposeRequest) returns (SetProtocolPurposeResponse) {}

    // Links an epi2me workflow reference to a run id.
    //
    // Since 1.15
    rpc add_epi2me_workflow (AddEpi2meWorkflowRequest) returns (AddEpi2meWorkflowResponse) {}

    // List all used protocol group ids used in any previous protocol on the box.
    //
    // Since 3.2
    rpc list_protocol_group_ids(ListProtocolGroupIdsRequest) returns (ListProtocolGroupIdsResponse) {}
}

message ProtocolRunUserInfo {
    // The group which the experiment should be held in.
    //
    // note: This value could be unset if a user did not specify a group_id when starting the protocol.
    google.protobuf.StringValue protocol_group_id = 1;

    // sample_id created by the user
    google.protobuf.StringValue sample_id = 2;
}

message StartProtocolRequest {
    // The identifier of the protocol, as provided by list_protocols().
    string identifier = 1 [(rpc_required) = true];

    // The arguments to pass to the protocol.
    repeated string args = 2;

    // User input describing the protocol.
    ProtocolRunUserInfo user_info = 3;
}

message StartProtocolResponse {
    // UUID generated when the protocol is started, to uniquely represent this protocol instance
    string run_id = 1;
}

message StopProtocolRequest {
    // Specify how any running acquisition should
    // be handled when stopping the protocol.
    //
    // Protocol state will enter PROTOCOL_WAITING_FOR_ACQUISITION whilst any running
    // acquisition is finished.
    //
    // If a script ends on its own any analysis that was started is stopped, and it
    // is allowed to catchup. If the caller wants to end catchup they can call stop_protocol
    // to end catchup.
    //
    // Since 1.15
    acquisition.StopRequest.DataAction data_action_on_stop = 1;
}

message StopProtocolResponse {
}

message ListProtocolsRequest {
    // If this is false, then will try to use the cached value of the protocol list where possible
    // (still subject to changes in flow cell).
    // If this is true, then will force a reload of the protocol list
    //
    // Defaults to false
    bool force_reload = 1;
}

message ProtocolInfo {
    message TagValue {
        oneof tag_value {
            string string_value = 1;
            bool bool_value = 2;
            int64 int_value = 3;
            double double_value = 4;
            string array_value = 5;
            string object_value = 6;
        }
    }
    message TagExtractionResult {
        bool success = 1;
        string error_report = 2;
    }

    string identifier = 1;
    map<string,TagValue> tags = 2;
    string name = 3;
    TagExtractionResult tag_extraction_result = 4;
}

message ListProtocolsResponse {
    repeated ProtocolInfo protocols = 1;
}

message WaitForFinishedRequest {
    enum NotificationState {
        // Request return just after the protocol has temrinated, including any acquisition periods completing.
        NOTIFY_ON_TERMINATION = 0;

        // Request return prior to the script being termiated.
        // note: will try to return 5s before killing the protocol script.
        NOTIFY_BEFORE_TERMINATION = 1;

        // Notify as the protocol script finishes, not waiting for any in progress acquisition to complete.
        NOTIFY_ON_SCRIPT_TERMINATION = 2;
    };

    // Only consider a specific protocol run.
    string run_id = 1 [(rpc_required) = true];

    // Control what to wait for.
    //
    // Specifying NOTIFY_BEFORE_TERMINATION allows a caller to be notified the script will be ended _soon_,
    // and do final work to end cleanly.
    //
    // Since 1.11
    NotificationState state = 2;

    // Timeout to wait for finished, if the timeout expires before the protocol is complete (in the state requested)
    // then the response returns.
    //
    // By default the timeout will wait forever.
    //
    // Since 1.15
    float timeout = 3;
}

message GetRunInfoRequest {
    // The protocol run to get information about.
    string run_id = 1;
}

enum ProtocolState {
    // The protocol is still running.
    PROTOCOL_RUNNING = 0;

    // The protocol is waiting for the device to reach temperature
    //
    // Since 1.15
    PROTOCOL_WAITING_FOR_TEMPERATURE = 4;

    // Occurs when data protocol has stopped (either from a explicit rpc request or the script naturally ended)
    // and data is still being processed (albacore is still in catchup and processing reads).
    PROTOCOL_WAITING_FOR_ACQUISITION = 5;

    // The protocol finished on its own and did not report an error.
    //
    // This is determined by the protocol process exiting with a zero exit code.
    PROTOCOL_COMPLETED = 1;

    // The protocol was terminated by the user.
    PROTOCOL_STOPPED_BY_USER = 2;

    // The protocol finished on its own and reported an error.
    //
    // This is determined by the protocol process exiting with a non-zero exit code or because of a
    // signal. Often, this will be because an exception was raised in the Python code and not
    // caught, but could also indicate that the Python process crashed or was killed by some
    // mechanism other than by MinKNOW.
    PROTOCOL_FINISHED_WITH_ERROR = 3;

    // The protocol was terminated because the sequencing device encountered an error.
    PROTOCOL_FINISHED_WITH_DEVICE_ERROR = 6;

    // The protocol was terminated because MinKNOW could not send telemetry to start acquisition.
    PROTOCOL_FINISHED_UNABLE_TO_SEND_TELEMETRY = 7;
}

message Epi2meWorkflowReference {
    // The unique identifier for a workflow ( unique to a specific instance of epi2me )
    int64 id = 1;

    // URL that links to the workflow report. Syntax for a local workflow: file:// otherwise: http(s)://
    string url = 2;
}

message ProtocolRunInfo {
    // The unique identifier assigned to this run.
    //
    // This is guaranteed to be made of ASCII characters, and at most 40 characters. It is globally
    // unique across all protocols runs on all MinKNOW instances.
    string run_id = 1;

    // The identifier of the protocol, as passed to start_protocol().
    string protocol_id = 2;

    // The arguments passed to start_protocol().
    repeated string args = 3;

    // Output location for protocol data (eg. reads).
    //
    // Since 1.16.
    string output_path = 11;

    // Indicates the current state of the protocol run.
    ProtocolState state = 4;

    // When the protocol was started (UTC).
    google.protobuf.Timestamp start_time = 5;

    // When the protocol script terminated (UTC).
    //
    // Unset if the protocol script is still running.
    //
    // Note that the protocol may still run until final acquisiton completes.
    google.protobuf.Timestamp script_end_time = 9;

    // When the protocol terminated (UTC), indicating both the
    // protocol script and the final acquisition were completed.
    //
    // Unset if the protocol is still running.
    google.protobuf.Timestamp end_time = 6;

    // A list of acquisition periods started whilst this protocol was running.
    //
    repeated string acquisition_run_ids = 7;

    // User specified information associated with the protocol at start time.
    //
    // Since 1.11.
    ProtocolRunUserInfo user_info = 8;

    // List of workflows from epi2me associated with this protocol
    //
    // Since 1.15.
    repeated Epi2meWorkflowReference epi2me_workflows = 10;

    // Information about the device a protocol was started with
    //
    // Since 3.4
    device.GetDeviceInfoResponse device = 12;

    // Information about the flow cell a protocol was started with
    //
    // Since 3.4
    device.GetFlowCellInfoResponse flow_cell = 13;
}

message ListProtocolRunsRequest {
}

message ListProtocolRunsResponse {
    repeated string run_ids = 1;
}
message GetCurrentProtocolRunRequest {
    
}

message GetCurrentProtocolRunResponse {
    ProtocolRunInfo run_info = 3;
}

message WatchCurrentProtocolRunRequest {
    
}

message GetContextInfoRequest {
    
}

message GetContextInfoResponse {
    map<string, string> context_info = 1;
}

message SetContextInfoRequest {
    map<string, string> context_info = 1;
}

message SetContextInfoResponse {
    
}

message GetSampleIdRequest {
    
}

message GetSampleIdResponse {
    string sample_id = 1;
}

message SetSampleIdRequest {
    string sample_id = 1;
}

message SetSampleIdResponse {
    
}

message GetProtocolPurposeRequest {
    
}

message GetProtocolPurposeResponse {
    string purpose = 1;
}

message SetProtocolPurposeRequest {
    string purpose = 1;
}

message SetProtocolPurposeResponse {
    
}

message AddEpi2meWorkflowRequest {
    string run_id = 1 [(rpc_required) = true];

    Epi2meWorkflowReference epi2me_workflow = 2 [(rpc_required) = true];
}

message AddEpi2meWorkflowResponse {
}

message ListProtocolGroupIdsRequest {
}

message ListProtocolGroupIdsResponse {
    // A list of protocol group ids used in any
    // protocol started on this instance of minknow.
    //
    repeated string protocol_group_ids = 1;
}
