// Copyright 2021 Lightbend Inc.

// gRPC interface for common messages used in protocols between the proxy and
// the user.

syntax = "proto3";

package akkaserverless.component;

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

import "google/protobuf/any.proto";
import "google/protobuf/descriptor.proto";

// Transport-specific metadata associated with a message.
//
// The semantics of the metadata are not defined in this protocol, but rather,
// depend on the transport on which a particular instance of the metadata maps
// to. What keys or values are allowed or disallowed, whether duplicate values
// for the same key are allowed and how they are handled, and whether key names
// are case sensitive or not, are all undefined in the context of the Akka
// Serverless protocol.
//
// If a metadata entry associated with a message can't be expressed in an
// underlying transport, for example, due to invalid characters in a key or
// value, the behavior of the proxy is undefined. This is because metadata is
// transport specific, so if the user function chooses to use metadata, it is
// choosing to be specific to a particular transport, which is beyond the scope
// of the Akka Serverless protocol, and it's therefore the user function's
// responsibility to adhere to the semantics of that transport. The proxy MAY
// decide to drop metadata entries if it knows they are invalid or unsupported.
// If a metadata entry is dropped, the proxy MAY inform the user function that
// the entry was dropped by sending an error message to the
// Discovery.ReportError gRPC call.
//
// The metadata MAY also contain CloudEvent metadata. If a message comes from an
// Akka Serverless event source, the Akka Serverless proxy MUST attach
// CloudEvent metadata to it if the event doesn't already have CloudEvent
// metadata attached to it. This metadata SHALL be encoded according to the
// binary mode of the CloudEvent HTTP protocol binding, which can be found here:
//
// https://github.com/cloudevents/spec/blob/master/http-protocol-binding.md
//
// The Akka Serverless proxy MAY synthesize appropriate values for Akka
// Serverless metadata if no equivalent metadata exists in the event source, for
// example, if there is no type, the Akka Serverless proxy MAY use the name of
// the gRPC message as the CloudEvent type, and if there is no source, the Akka
// Serverless proxy MAY use the name of the topic as the source.
//
// If an incoming message does have CloudEvent metadata attached to it, the Akka
// Serverless proxy MUST transcode that CloudEvent metadata to the HTTP protocol
// binding as described above.
//
// Messages sent from the user function to an event destination MAY include
// CloudEvent metadata. If they include any CloudEvent metadata, they MUST
// include all required CloudEvent attributes, including id, source, specversion
// and type. The behavior of the proxy is undefined if some of these attributes,
// but not others, are included - the proxy MAY ignore them all, or MAY generate
// values itself, but SHOULD NOT fail sending the message. If the destination
// for the message is an event destination, the Akka Serverless proxy MUST
// transcode the supplied Akka Serverless metadata to a binding appropriate for
// the underlying transport for that event destination, it MUST NOT pass the
// CloudEvent metadata as is unless the transport uses the same binding rules.
message Metadata {
  // The metadata entries.
  repeated MetadataEntry entries = 1;
}

// A metadata entry.
message MetadataEntry {
  // Key for the entry. Valid keys are determined by the underlying transport.
  string key = 1;
  // The value.
  oneof value {
    // A string value. Valid values are determined by the underlying transport.
    //
    // If the transport does not support string values, the behavior of the Akka
    // Serverless proxy is undefined from the point of view of this protocol. If
    // there is a convention in the protocol for encoding string values as UTF-8
    // bytes, then the Akka Serverless proxy MAY do that.
    string string_value = 2;
    // A bytes value. Valid values are determined by the underlying transport.
    //
    // If the transport does not support bytes values, the behavior of the Akka
    // Serverless proxy is undefined from the point of view of this protocol. If
    // there is a convention in the protocol for encoding bytes values as Base64
    // encoded strings, then the Akka Serverless proxy MAY do that.
    bytes bytes_value = 3;
  }
}

// A reply to the sender.
message Reply {
  // The reply payload
  google.protobuf.Any payload = 1;
  // Metadata for the reply
  //
  // Not all transports support per message metadata, for example, gRPC doesn't.
  // The Akka Serverless proxy MAY ignore the metadata in this case, or it MAY
  // lift the metadata into another place, for example, in gRPC, a unary call
  // MAY have its reply metadata placed in the headers of the HTTP response, or
  // the first reply to a streamed call MAY have its metadata placed in the
  // headers of the HTTP response.
  //
  // If the metadata is ignored, the Akka Serverless proxy MAY notify the user
  // function by sending an error message to the Discovery.ReportError gRPC
  // call.
  Metadata metadata = 2;
}

// Forwards handling of this request to another component.
message Forward {
  // The name of the service to forward to.
  string service_name = 1;
  // The name of the command.
  string command_name = 2;
  // The payload.
  google.protobuf.Any payload = 3;
  // The metadata to include with the forward
  Metadata metadata = 4;
}

// An action for the client
// (see ActionResponse in action.proto)
message ClientAction {
  oneof action {
    // Send a reply
    Reply reply = 1;
    // Forward to another component
    Forward forward = 2;
    // Send a failure to the client
    Failure failure = 3;
  }
}

// A side effect to be done after this command is handled.
message SideEffect {
  // The name of the service to perform the side effect on.
  string service_name = 1;
  // The name of the command.
  string command_name = 2;
  // The payload of the command.
  google.protobuf.Any payload = 3;
  // Whether this side effect should be performed synchronously, ie, before the
  // reply is eventually sent, or not.
  bool synchronous = 4;
  // The metadata to include with the side effect
  Metadata metadata = 5;
}

message StreamCancelled {
  // The ID of the component
  string component_id = 1;
  // The command id
  int64 id = 2;
}

// A failure reply. If this is returned, it will be translated into a gRPC
// unknown error with the corresponding description if supplied.
message Failure {
  // The id of the command being replied to. Must match the input command.
  int64 command_id = 1;
  // A description of the error.
  string description = 2;
  // Whether this failure should trigger an entity restart.
  bool restart = 3;
  // The gRPC status code.
  //
  // If this failure is being sent as an action for a gRPC response, and this
  // is non zero, then this is the code that will be used.
  //
  // Note that a status code of zero in gRPC means OK. Since this is a failure,
  // zero passed here is not interpreted to mean OK, but rather indicates that
  // no gRPC status code is explicitly specified. A status code of 2, meaning
  // unknown error, will be sent by default.
  //
  // When HTTP transcoding is being used, the gRPC status code will be
  // translated to an equivalent HTTP status code. HTTP status codes MUST NOT
  // be passed in this field.
  //
  // See https://grpc.github.io/grpc/core/md_doc_statuscodes.html for a list
  // of gRPC status codes and their meanings.
  int32 grpc_status_code = 4;
}
