Documentation ¶
Overview ¶
Package signals implements functions for emitting and receiving synchronous signals.
A signal is always sent by a single sender, but can reach an arbitrary number of receivers.
Users should define typed signals for each required argument type using non-exported types but with exported methods. Then, use a public anonymous structure to export all signals. This allows packages to export either listen/emit or listen only signals.
First, define your typed signal:
// Message is exported, so callers can use the data type emitted // by the signal. type Message struct { ... } // messageSignal is unexported, but contains exported methods type messageSignal struct { s *signals.Signal } // Listen is exported, so other packages can listen for this signal func(s *messageSignal) Listen(handler func(*Message)) signals.Listener { return s.s.Listen(func(data interface{}) { handler(data.(*Message))}) }) // emit is unexported, so only this package can emit the signal. If // other packages should be able to emit the signal, just export it // as Emit(). func(s *messageSignal) emit(msg *Message) { s.s.Emit(msg) }
Then, define a package level exported struct which will hold all your package signals:
var Signals = struct{ MessageReceived *messageSignal MessageSent *messageSignal }{ &messageSignal{signals.New("message-received")}, &messageSignal{signals.New("message-sent")}, }
When you want to emit a signal, just call its emit method:
Signals.MessageReceived.emit(&Message{...})
On the other hand, listeners will be able to register themselves like:
your.package.Signals.MessageReceived.Listen(func(msg *your.package.Message{ ... }))
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Listener ¶
type Listener interface {
Remove()
}
Listener is the interface returned by Listen. Call Remove to stop listening for the signal.
type Signal ¶
type Signal struct {
// contains filtered or unexported fields
}
Signal allows emitting and receiving signals. Use New to create a new Signal. Note that Signal should usually be wrapped in another type which emits/listens for a typed signal. See the package documentation for details.
Example ¶
package main import ( "fmt" "time" "gondola/signals" ) // Message is exported, so callers can use the type emitted // by the signal. type Message struct { Text string Timestamp time.Time } // messageSignal is unexported, so only this package can create // instances. However, it contains exported methods to allow // listening and or emitting signals from calling packages. type messageSignal struct { s *signals.Signal } // Listen is exported, so callers can listen to this signal. func (s *messageSignal) Listen(handler func(*Message)) signals.Listener { return s.s.Listen(func(data interface{}) { handler(data.(*Message)) }) } // emit is unexported, so only this package can emit the signal. Note that // a package might choose to export Emit too. func (s *messageSignal) emit(msg *Message) { s.s.Emit(msg) } // Signals is exported, so package callers can access it and its fields // as e.g. pkg.Signals.MessageReceived.Listen(...) var Signals = struct { MessageReceived *messageSignal }{ &messageSignal{signals.New("message-received")}, } func main() { listener := Signals.MessageReceived.Listen(func(msg *Message) { fmt.Println(msg.Text, msg.Timestamp.Unix()) }) Signals.MessageReceived.emit(&Message{ Text: "hello", Timestamp: time.Unix(42, 0), }) listener.Remove() // Emitting again won't cause the listener to be called // since the listener was removed. Signals.MessageReceived.emit(&Message{ Text: "hello again", Timestamp: time.Unix(42*2, 0), }) }
Output: hello 42
func New ¶
New returns a new Signal. The name parameter will be combined with the caller package name. e.g. ("mysignal" from package example.com/pkg/subpkg will become "example.com/pkg/subpkg.mysignal"). Note that the name is optional and right now is only used in debug messages.