/actors

A actor framework and KSP processor/generator for kotlin.

Primary LanguageKotlinApache License 2.0Apache-2.0

Quality Gate Status Coverage Reliability Rating Security Rating Maintainability Rating

wakatime

Actors

A simple actor based programming framework for kotlin. Currently only compatible with kotlin jvm.

Warning

This project is still experimental and lacking in features. The implementation still needs some work and refactoring, especially the KSP processor. This framework is not ready for production use, there are no official maven releases yet!

Example (Experimental)

Please note, this API is still experimental.

PersonState.kt

import com.bethibande.actors.annotations.ActorState

/**
 * An actor implementation will be generated from this class.
 */
@ActorState
data class PersonState(
    var name: String,
    var age: Int,
)

Main.kt, usage of the generated code

runBlocking {
    // Create actor-system
    val system = Person.localActorSystem()
    // Create a new actor
    val person: Person = system.new(PersonState("Max", 17))

    // Use the actor
    println("${person.getName()}: ${person.getAge()}")
    person.setAge(18)
    println("${person.getName()}: ${person.getAge()}")

    // Custom behavior/command (see com.bethibande.example.person.CustomFunctionality.kt)
    val (name, age) = person.getNameAndAge()
    println("Custom: $name, $age")

    // Send close command
    person.close()
}

CustomFunctionality.kt, adds custom functionallity / commands to the generated actor

import com.bethibande.actors.Actor
import com.bethibande.actors.behavior.Behavior
import com.bethibande.example.person.command.PersonCommand
import kotlinx.coroutines.CompletableDeferred

data class PersonCommandGetNameAndAge(
    val deferred: CompletableDeferred<Pair<String, Int>>
): PersonCommand {
    companion object: Behavior<PersonCommandGetNameAndAge, PersonState> {
        init {
            // Adds the behavior to all actors of the Person type, also affects existing actors.
            Person.BehaviorMap.add(PersonCommandGetNameAndAge::class.java, this)
        }

        override suspend fun accept(
            command: PersonCommandGetNameAndAge,
            state: PersonState,
            actor: Actor<PersonCommandGetNameAndAge, PersonState>
        ) {
            command.deferred.complete(state.name to state.age)
        }
    }
}

suspend fun Person.getNameAndAge(): Pair<String, Int> {
    val deferred = CompletableDeferred<Pair<String, Int>>()
    send(PersonCommandGetNameAndAge(deferred))
    return deferred.await()
}

Dependencies