signals

package
v0.0.0-...-9431910 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 28, 2021 License: MPL-2.0 Imports: 4 Imported by: 0

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

func New(name ...string) *Signal

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.

func (*Signal) Emit

func (s *Signal) Emit(data interface{})

Emit emits this signal, calling all registered listeners. Note that this function should only be called from a typed Signal wrapping it. See the package documentation for examples.

func (*Signal) Listen

func (s *Signal) Listen(handler func(interface{})) Listener

Listen is a shorthand for Listen(signame, handler), where signame is the signal name received in New().

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL