mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-10-05 18:03:09 +02:00
In this commit, we add a series of examples that show how the package can be used in the wild. They can be run as normal Example tests.
148 lines
3.9 KiB
Go
148 lines
3.9 KiB
Go
package actor_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/lightningnetwork/lnd/actor"
|
|
"github.com/lightningnetwork/lnd/fn/v2"
|
|
)
|
|
|
|
// CounterMsg is a message type for the stateful counter actor.
|
|
// It can be used to increment the counter or get its current value.
|
|
type CounterMsg struct {
|
|
actor.BaseMessage
|
|
Increment int
|
|
GetValue bool
|
|
Who string
|
|
}
|
|
|
|
// MessageType implements actor.Message.
|
|
func (m CounterMsg) MessageType() string { return "CounterMsg" }
|
|
|
|
// CounterResponse is a response type for the counter actor.
|
|
type CounterResponse struct {
|
|
Value int
|
|
Responder string
|
|
}
|
|
|
|
// StatefulCounterActor demonstrates an actor that maintains internal state (a
|
|
// counter) and processes messages to modify or query that state.
|
|
type StatefulCounterActor struct {
|
|
counter int
|
|
actorID string
|
|
}
|
|
|
|
// NewStatefulCounterActor creates a new counter actor.
|
|
func NewStatefulCounterActor(id string) *StatefulCounterActor {
|
|
return &StatefulCounterActor{
|
|
actorID: id,
|
|
}
|
|
}
|
|
|
|
// Receive is the message handler for the StatefulCounterActor.
|
|
// It implements the actor.ActorBehavior interface implicitly when wrapped.
|
|
func (s *StatefulCounterActor) Receive(ctx context.Context,
|
|
msg CounterMsg) fn.Result[CounterResponse] {
|
|
|
|
if msg.Increment > 0 {
|
|
// For increment, we can just acknowledge or return the new
|
|
// value. Messages are sent serially, so we don't need to worry
|
|
// about a mutex here.
|
|
s.counter += msg.Increment
|
|
|
|
return fn.Ok(CounterResponse{
|
|
Value: s.counter,
|
|
Responder: s.actorID,
|
|
})
|
|
}
|
|
|
|
if msg.GetValue {
|
|
return fn.Ok(CounterResponse{
|
|
Value: s.counter,
|
|
Responder: s.actorID,
|
|
})
|
|
}
|
|
|
|
return fn.Err[CounterResponse](fmt.Errorf("invalid CounterMsg"))
|
|
}
|
|
|
|
// ExampleStructActor demonstrates creating an actor whose behavior is defined
|
|
// by a struct with methods, allowing it to maintain internal state.
|
|
func ExampleStructActor() {
|
|
system := actor.NewActorSystem()
|
|
defer system.Shutdown()
|
|
|
|
counterServiceKey := actor.NewServiceKey[CounterMsg, CounterResponse](
|
|
"struct-counter-service",
|
|
)
|
|
|
|
// Create an instance of our stateful actor logic.
|
|
actorID := "counter-actor-1"
|
|
counterLogic := NewStatefulCounterActor(actorID)
|
|
|
|
// Spawn the actor.
|
|
// The counterLogic instance itself satisfies the ActorBehavior
|
|
// interface because its Receive method matches the required signature.
|
|
counterRef := counterServiceKey.Spawn(system, actorID, counterLogic)
|
|
fmt.Printf("Actor %s spawned.\n", counterRef.ID())
|
|
|
|
// Send messages to increment the counter.
|
|
for i := 1; i <= 3; i++ {
|
|
askCtx, askCancel := context.WithTimeout(
|
|
context.Background(), 1*time.Second,
|
|
)
|
|
futureResp := counterRef.Ask(askCtx,
|
|
CounterMsg{
|
|
Increment: i,
|
|
Who: fmt.Sprintf("Incrementer-%d", i),
|
|
},
|
|
)
|
|
awaitCtx, awaitCancel := context.WithTimeout(
|
|
context.Background(), 1*time.Second,
|
|
)
|
|
resp := futureResp.Await(awaitCtx)
|
|
|
|
resp.WhenOk(func(r CounterResponse) {
|
|
fmt.Printf("Incremented by %d, new value: %d "+
|
|
"(from %s)\n", i, r.Value, r.Responder)
|
|
})
|
|
resp.WhenErr(func(e error) {
|
|
fmt.Printf("Error incrementing: %v\n", e)
|
|
})
|
|
awaitCancel()
|
|
askCancel()
|
|
}
|
|
|
|
// Send a message to get the current value.
|
|
askCtx, askCancel := context.WithTimeout(
|
|
context.Background(), 1*time.Second,
|
|
)
|
|
futureResp := counterRef.Ask(
|
|
askCtx, CounterMsg{GetValue: true, Who: "Getter"},
|
|
)
|
|
|
|
awaitCtx, awaitCancel := context.WithTimeout(
|
|
context.Background(), 1*time.Second,
|
|
)
|
|
|
|
finalValueResp := futureResp.Await(awaitCtx)
|
|
finalValueResp.WhenOk(func(r CounterResponse) {
|
|
fmt.Printf("Final counter value: %d (from %s)\n",
|
|
r.Value, r.Responder)
|
|
})
|
|
finalValueResp.WhenErr(func(e error) {
|
|
fmt.Printf("Error getting value: %v\n", e)
|
|
})
|
|
awaitCancel()
|
|
askCancel()
|
|
|
|
// Output:
|
|
// Actor counter-actor-1 spawned.
|
|
// Incremented by 1, new value: 1 (from counter-actor-1)
|
|
// Incremented by 2, new value: 3 (from counter-actor-1)
|
|
// Incremented by 3, new value: 6 (from counter-actor-1)
|
|
// Final counter value: 6 (from counter-actor-1)
|
|
}
|