/
system.go
116 lines (100 loc) · 3.69 KB
/
system.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package actor
import (
"context"
"sync"
"time"
)
// System is a hierarchical group of actors.
type System struct {
id string
*Ref
refsLock sync.RWMutex
refs map[Address]*Ref
}
// NewSystem constructs a new actor system and starts it.
func NewSystem(id string) *System {
return NewSystemWithRoot(id, &rootActor{})
}
// NewSystemWithRoot constructs a new actor system with the specified root actor and starts it.
func NewSystemWithRoot(id string, actor Actor) *System {
system := &System{id: id, refs: make(map[Address]*Ref)}
system.Ref = newRef(system, nil, rootAddress, actor)
return system
}
// Tell sends the specified message to the actor (fire-and-forget semantics). The context's sender
// is set to `nil`.
func (s *System) Tell(actor *Ref, message Message) {
if actor == nil {
return
}
actor.tell(context.Background(), nil, message)
}
// TellAt sends the specified message to the actor (fire-and-forget semantics) at the provided
// address. The context's sender is set to `nil`.
func (s *System) TellAt(addr Address, message Message) {
s.Tell(s.Get(addr), message)
}
// Ask sends the specified message to the actor, returning a future to the result of the call. The
// context's sender is set to `nil`.
func (s *System) Ask(actor *Ref, message Message) Response {
if actor == nil {
return emptyResponse(nil)
}
return actor.ask(context.Background(), nil, message)
}
// AskAt sends the specified message to the actor at the provided address, returning a future to the
// result of the call. The context's sender is set to `nil`. If an actor does not exist at the exact
// address we attempt to lookup and send the message to an actor registered at the sibling wildcard
// address instead.
func (s *System) AskAt(addr Address, message Message) Response {
actorAddr := s.Get(addr)
if actorAddr == nil {
actorAddr = s.Get(addr.Parent().Child("*"))
}
return s.Ask(actorAddr, message)
}
// AskAll sends the specified message to all actors, returning a future to all results of the call.
// Results are returned in arbitrary order. The result channel is closed after all actors respond.
// The context's sender is set to `nil`.
func (s *System) AskAll(message Message, actors ...*Ref) Responses {
return askAll(context.Background(), message, nil, nil, actors)
}
// AskAllTimeout sends the specified message to all actors, returning a future to all results of the
// call. Results are returned in arbitrary order. The result channel is closed after all actors
// respond. The context's sender is set to `nil`. If the timeout is reached, nil responses are
// returned.
func (s *System) AskAllTimeout(message Message, timeout time.Duration, actors ...*Ref) Responses {
return askAll(context.Background(), message, &timeout, nil, actors)
}
// Get returns the actor reference with the id, or nil if no actor with that id is found.
func (s *System) Get(address Address) *Ref {
if address == rootAddress {
return s.Ref
}
s.refsLock.RLock()
defer s.refsLock.RUnlock()
return s.refs[address]
}
// ActorOf adds the actor with the provided address.
// The second return value denotes whether a new actor was created or not.
func (s *System) ActorOf(address Address, actor Actor) (*Ref, bool) {
parent := s.Get(address.Parent())
if parent == nil {
return nil, false
}
resp := s.Ask(parent, createChild{address: address, actor: actor})
if resp.Empty() {
return nil, false
}
created := resp.Get().(childCreated)
return created.child, created.created
}
// MustActorOf adds the actor with the provided address.
// It panics if a new actor was not created.
func (s *System) MustActorOf(address Address, actor Actor) *Ref {
ref, created := s.ActorOf(address, actor)
if !created {
panic("actor was not created")
}
return ref
}