syntax = "proto3";

package eigr.functions.protocol.actors;

import "google/protobuf/any.proto";

option java_package = "io.eigr.functions.protocol.actors";
option go_package = "github.com/eigr/go-support/eigr/actors;actors";

message Registry {
    map<string, Actor> actors = 1;
}

message ActorSystem {
    string name = 1;
    Registry registry = 2;
}

// A strategy for save state.
message ActorSnapshotStrategy {
    oneof strategy {
        // the timeout strategy.
        TimeoutStrategy timeout = 1;
    }
}

// A strategy which a user function's entity is passivated.
message ActorDeactivationStrategy {
    oneof strategy {
        // the timeout strategy.
        TimeoutStrategy timeout = 1;
    }
}

// A strategy based on a timeout. 
message TimeoutStrategy {
    // The timeout in millis
    int64 timeout = 1;
}

// A command represents an action that the user can perform on an Actor. 
// Commands in supporting languages are represented by functions or methods.
// An Actor command has nothing to do with the semantics of Commands in a CQRS/EventSourced system. 
// It just represents an action that supporting languages can invoke.
message Command {

    // The name of the function or method in the supporting language that has been registered in Ator.
    string name = 1;
}

// A FixedTimerCommand is similar to a regular Command, its main differences are that it is scheduled to run at regular intervals 
// and only takes the actor's state as an argument.
// Timer Commands are good for executing loops that manipulate the actor's own state. 
// In Elixir or other languages in BEAM it would be similar to invoking Process.send_after(self(), atom, msg, timeout)
message FixedTimerCommand {

    // The time to wait until the command is triggered
    int32 seconds = 1;

    // See Command description Above
    Command command = 2;
}

message ActorState {
    map<string, string> tags = 1;
    google.protobuf.Any state = 2;
}

// TODO doc here
message Metadata {
    // A channel group represents a way to send commands to various actors 
    // that belong to a certain semantic group.
    string channel_group = 1;

    map<string, string> tags = 2;
}

// The type that defines the runtime characteristics of the Actor.
// Regardless of the type of actor it is important that 
// all actors are registered during the proxy and host initialization phase.
enum Kind {
    // When no type is informed, the default to be assumed will be the Singleton pattern.
    UNKNOW_KIND = 0;

    // Abstract actors are used to create children of this based actor at runtime
    ABSTRACT = 1;

    // Singleton actors as the name suggests have only one real instance of themselves running 
    // during their entire lifecycle. That is, they are the opposite of the Abstract type Actors.
    SINGLETON = 2;
    
    // Pooled Actors are similar to abstract actors, but unlike them, 
    // their identifying name will always be the one registered at the system initialization stage. 
    // The great advantage of Pooled actors is that they have multiple instances of themselves 
    // acting as a request service pool.
    // Pooled actors are also stateless actors, that is, they will not have their 
    // in-memory state persisted via Statesstore. This is done to avoid problems 
    // with the correctness of the stored state.
    // Pooled Actors are generally used for tasks where the Actor Model would perform worse 
    // than other concurrency models and for tasks that do not require state concerns. 
    // Integration flows, data caching, proxies are good examples of use cases 
    // for this type of Actor.
    POOLED = 3;
    
    // Reserved for future use
    PROXY = 4;
}

message ActorSettings {

    // Indicates the type of Actor to be configured.
    Kind kind = 1;

    // Indicates whether an actor's state should be persisted in a definitive store.
    bool stateful = 2;

    // Snapshot strategy
    ActorSnapshotStrategy snapshot_strategy = 3;

    // Deactivate strategy
    ActorDeactivationStrategy deactivation_strategy = 4;

    // When kind is POOLED this is used to define minimun actor instances
    int32 min_pool_size = 5;

    // When kind is POOLED this is used to define maximum actor instances
    int32 max_pool_size = 6;
}

message ActorId {
    // The name of a Actor Entity.
    string name = 1;

    // Name of a ActorSystem
    string system = 2;

    // When the Actor is of the Abstract type, 
    // the name of the parent Actor must be informed here.
    string parent = 3;
}

message Actor {
    // Actor Identification
    ActorId id = 1;

    // A Actor state.
    ActorState state = 2;

    // Actor metadata
    Metadata metadata = 6;

    // Actor settings.
    ActorSettings settings = 3;

    // The commands registered for an actor
    repeated Command commands = 4;

    // The registered timer commands for an actor.
    repeated FixedTimerCommand timer_commands = 5;
}