// Copyright 2021 Lightbend Inc.

// gRPC interface for Event Sourced Entity user functions.

syntax = "proto3";

package akkaserverless.component.eventsourcedentity;

option go_package = "github.com/lightbend/akkaserverless-go-sdk/akkaserverless/entity;entity";
option java_package = "com.akkaserverless.protocol";

import "akkaserverless/component/component.proto";
import "akkaserverless/component/entity/entity.proto";
import "google/protobuf/any.proto";

// The init message. This will always be the first message sent to the entity
// when it is loaded.
message EventSourcedInit {
  // The name of the service that this entity is a part of.
  string service_name = 1;
  // The ID of the entity.
  string entity_id = 2;
  // If present the entity should initialise its state using this snapshot.
  EventSourcedSnapshot snapshot = 3;
}

// A snapshot
message EventSourcedSnapshot {
  // The sequence number when the snapshot was taken.
  int64 snapshot_sequence = 1;
  // The snapshot.
  google.protobuf.Any snapshot = 2;
}

// An event. These will be sent to the entity when the entity starts up.
message EventSourcedEvent {
  // The sequence number of the event.
  int64 sequence = 1;
  // The event payload.
  google.protobuf.Any payload = 2;
}

// A request for a snapshot from the proxy.
//
// This can arrive at any time after init, including while a command is being processed.
message EventSourcedSnapshotRequest {
  // The ID of this request. The response should include this ID.
  int64 request_id = 1;
}

// A reply to a command.
message EventSourcedReply {
  // The id of the command being replied to. Must match the input command.
  int64 command_id = 1;
  // The action to take
  ClientAction client_action = 2;
  // Any side effects to perform
  repeated SideEffect side_effects = 3;
  // A list of events to persist - these will be persisted before the reply
  // is sent.
  repeated google.protobuf.Any events = 4;
  // An optional snapshot to persist. It is assumed that this snapshot will have
  // the state of any events in the events field applied to it. It is illegal to
  // send a snapshot without sending any events.
  google.protobuf.Any snapshot = 5;
}

// The reply to an EventSourcedSnapshotRequest
message EventSourcedSnapshotReply {
  // The ID of this request. Must match the id from the request that this is in reply to.
  int64 request_id = 1;
  // The snapshot.
  //
  // The state in this snapshot must not include any applied events that have not
  // been sent in an EventSourcedReply message.
  google.protobuf.Any snapshot = 2;
}

// Input message type for the gRPC stream in.
message EventSourcedStreamIn {
  oneof message {
    EventSourcedInit init = 1;
    EventSourcedEvent event = 2;
    entity.Command command = 3;
    EventSourcedSnapshotRequest snapshot_request = 4;
  }
}

// Output message type for the gRPC stream out.
message EventSourcedStreamOut {
  oneof message {
    EventSourcedReply reply = 1;
    Failure failure = 2;
    EventSourcedSnapshotReply snapshot_reply = 3;
  }
}

// Service that the SDK (in the user function) implements to make event-sourced
// entities available to the proxy
service EventSourcedEntities {
  // The stream. One stream will be established per active entity. Once
  // established, the first message sent will be Init, which contains the entity
  // ID, and, if the entity has previously persisted a snapshot, it will contain
  // that snapshot. It will then send zero to many event messages, one for each
  // event previously persisted. The entity is expected to apply these to its
  // state in a deterministic fashion. Once all the events are sent, one to many
  // commands are sent, with new commands being sent as new requests for the
  // entity come in. The entity is expected to reply to each command with
  // exactly one reply message. The entity should reply in order, and any events
  // that the entity requests to be persisted the entity should handle itself,
  // applying them to its own state, as if they had arrived as events when the
  // event stream was being replayed on load.
  rpc Handle(stream EventSourcedStreamIn) returns (stream EventSourcedStreamOut);
}
