signals

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 23, 2024 License: MIT Imports: 2 Imported by: 5

README

Signals

The signals a robust, dependency-free go library that provides simple, thin, and user-friendly pub-sub kind of in-process event system for your Go applications. It allows you to generate and emit signals (synchronously or asynchronously) as well as manage listeners.

💯 100% test coverage 💯

GoReportCard example made-with-Go GoDoc reference example

Installation

go get github.com/maniartech/signals

Usage

package main

import (
  "context"
  "fmt"
  "github.com/maniartech/signals"
)

var RecordCreated = signals.New[Record]()
var RecordUpdated = signals.New[Record]()
var RecordDeleted = signals.New[Record]()

func main() {

  // Add a listener to the RecordCreated signal
  RecordCreated.AddListener(func(ctx context.Context, record Record) {
    fmt.Println("Record created:", record)
  }, "key1") // <- Key is optional useful for removing the listener later

  // Add a listener to the RecordUpdated signal
  RecordUpdated.AddListener(func(ctx context.Context, record Record) {
    fmt.Println("Record updated:", record)
  })

  // Add a listener to the RecordDeleted signal
  RecordDeleted.AddListener(func(ctx context.Context, record Record) {
    fmt.Println("Record deleted:", record)
  })

  ctx := context.Background()

  // Emit the RecordCreated signal
  RecordCreated.Emit(ctx, Record{ID: 1, Name: "John"})

  // Emit the RecordUpdated signal
  RecordUpdated.Emit(ctx, Record{ID: 1, Name: "John Doe"})

  // Emit the RecordDeleted signal
  RecordDeleted.Emit(ctx, Record{ID: 1, Name: "John Doe"})
}

Documentation

GoDoc

License

License

✨You Need Some Go Experts, Right? ✨

As a software development firm, ManiarTech® specializes in Golang-based projects. Our team has an in-depth understanding of Enterprise Process Automation, Open Source, and SaaS. Also, we have extensive experience porting code from Python and Node.js to Golang. We have a team of Golang experts here at ManiarTech® that is well-versed in all aspects of the language and its ecosystem. At ManiarTech®, we have a team of Golang experts who are well-versed in all facets of the technology.

In short, if you're looking for experts to assist you with Golang-related projects, don't hesitate to get in touch with us. Send an email to contact@maniartech.com to get in touch.

👉🏼 Do you consider yourself an "Expert Golang Developer"? 👈🏼

If so, you may be interested in the challenging and rewarding work that is waiting for you. Use careers@maniartech.com to submit your resume.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AsyncSignal added in v1.1.0

type AsyncSignal[T any] struct {
	BaseSignal[T]
	// contains filtered or unexported fields
}

AsyncSignal is a struct that implements the Signal interface. This is the default implementation. It provides the same functionality as the SyncSignal but the listeners are called in a separate goroutine. This means that all listeners are called asynchronously. However, the method waits for all the listeners to finish before returning. If you don't want to wait for the listeners to finish, you can call the Emit method in a separate goroutine.

func (*AsyncSignal[T]) Emit added in v1.1.0

func (s *AsyncSignal[T]) Emit(ctx context.Context, payload T)

Emit notifies all subscribers of the signal and passes the payload in a asynchronous way.

If the context has a deadline or cancellable property, the listeners must respect it. This means that the listeners should stop processing when the context is cancelled. While emtting it calls the listeners in separate goroutines, so the listeners are called asynchronously. However, it waits for all the listeners to finish before returning. If you don't want to wait for the listeners to finish, you can call the Emit method. Also, you must know that Emit does not guarantee the type safety of the emitted value.

Example:

signal := signals.New[string]()
signal.AddListener(func(ctx context.Context, payload string) {
	// Listener implementation
	// ...
})

signal.Emit(context.Background(), "Hello, world!")

type BaseSignal added in v1.1.0

type BaseSignal[T any] struct {
	// contains filtered or unexported fields
}

BaseSignal provides the base implementation of the Signal interface. It is intended to be used as an abstract base for underlying signal mechanisms.

Example:

type MyDerivedSignal[T any] struct {
	BaseSignal[T]
	// Additional fields or methods specific to MyDerivedSignal
}

func (s *MyDerivedSignal[T]) Emit(ctx context.Context, payload T) {
	// Custom implementation for emitting the signal
}

func (*BaseSignal[T]) AddListener added in v1.1.0

func (s *BaseSignal[T]) AddListener(listener SignalListener[T], key ...string) int

AddListener adds a listener to the signal. The listener will be called whenever the signal is emitted. It returns the number of subscribers after the listener was added. It accepts an optional key that can be used to remove the listener later or to check if the listener was already added. It returns -1 if the listener with the same key was already added to the signal.

Example:

signal := signals.New[int]()
count := signal.AddListener(func(ctx context.Context, payload int) {
	// Listener implementation
	// ...
}, "key1")
fmt.Println("Number of subscribers after adding listener:", count)

func (*BaseSignal[T]) Emit added in v1.1.0

func (s *BaseSignal[T]) Emit(ctx context.Context, payload T)

Emit is not implemented in BaseSignal and panics if called. It should be implemented by a derived type.

Example:

type MyDerivedSignal[T any] struct {
	BaseSignal[T]
	// Additional fields or methods specific to MyDerivedSignal
}

func (s *MyDerivedSignal[T]) Emit(ctx context.Context, payload T) {
	// Custom implementation for emitting the signal
}

func (*BaseSignal[T]) IsEmpty added in v1.1.0

func (s *BaseSignal[T]) IsEmpty() bool

IsEmpty checks if the signal has any subscribers. It returns true if the signal has no subscribers, and false otherwise. This can be used to check if there are any listeners before emitting a signal.

Example:

signal := signals.New[int]()
fmt.Println("Is signal empty?", signal.IsEmpty()) // Should print true
signal.AddListener(func(ctx context.Context, payload int) {
	// Listener implementation
	// ...
})
fmt.Println("Is signal empty?", signal.IsEmpty()) // Should print false

func (*BaseSignal[T]) Len added in v1.1.0

func (s *BaseSignal[T]) Len() int

Len returns the number of listeners subscribed to the signal. This can be used to check how many listeners are currently waiting for a signal. The returned value is of type int.

Example:

signal := signals.New[int]()
signal.AddListener(func(ctx context.Context, payload int) {
	// Listener implementation
	// ...
})
fmt.Println("Number of subscribers:", signal.Len())

func (*BaseSignal[T]) RemoveListener added in v1.1.0

func (s *BaseSignal[T]) RemoveListener(key string) int

RemoveListener removes a listener from the signal. It returns the number of subscribers after the listener was removed. It returns -1 if the listener was not found.

Example:

signal := signals.New[int]()
signal.AddListener(func(ctx context.Context, payload int) {
	// Listener implementation
	// ...
}, "key1")
count := signal.RemoveListener("key1")
fmt.Println("Number of subscribers after removing listener:", count)

func (*BaseSignal[T]) Reset added in v1.1.0

func (s *BaseSignal[T]) Reset()

Reset resets the signal by removing all subscribers from the signal, effectively clearing the list of subscribers. This can be used when you want to stop all listeners from receiving further signals.

Example:

signal := signals.New[int]()
signal.AddListener(func(ctx context.Context, payload int) {
	// Listener implementation
	// ...
})
signal.Reset() // Removes all listeners
fmt.Println("Number of subscribers after resetting:", signal.Len())

type Signal

type Signal[T any] interface {
	// Emit notifies all subscribers of the signal and passes the context and the payload.
	//
	// If the context has a deadline or cancellable property, the listeners
	// must respect it. If the signal is async (default), the listeners are called
	// in a separate goroutine.
	//
	// Example:
	//	signal := signals.New[int]()
	//	signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	})
	//	signal.Emit(context.Background(), 42)
	Emit(ctx context.Context, payload T)

	// AddListener adds a listener to the signal.
	//
	// The listener will be called whenever the signal is emitted. It returns the
	// number of subscribers after the listener was added. It accepts an optional key
	// that can be used to remove the listener later or to check if the listener
	// was already added. It returns -1 if the listener with the same key
	// was already added to the signal.
	//
	// Example:
	//	signal := signals.NewSync[int]()
	//	count := signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	})
	//	fmt.Println("Number of subscribers after adding listener:", count)
	AddListener(handler SignalListener[T], key ...string) int

	// RemoveListener removes a listener from the signal.
	//
	// It returns the number of subscribers after the listener was removed.
	// It returns -1 if the listener was not found.
	//
	// Example:
	//	signal := signals.NewSync[int]()
	//	signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	}, "key1")
	//	count := signal.RemoveListener("key1")
	//	fmt.Println("Number of subscribers after removing listener:", count)
	RemoveListener(key string) int

	// Reset resets the signal by removing all subscribers from the signal,
	// effectively clearing the list of subscribers.
	//
	// This can be used when you want to stop all listeners from receiving
	// further signals.
	//
	// Example:
	//	signal := signals.New[int]()
	//	signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	})
	//	signal.Reset() // Removes all listeners
	//	fmt.Println("Number of subscribers after resetting:", signal.Len())
	Reset()

	// Len returns the number of listeners subscribed to the signal.
	//
	// This can be used to check how many listeners are currently waiting for a signal.
	// The returned value is of type int.
	//
	// Example:
	//	signal := signals.NewSync[int]()
	//	signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	})
	//	fmt.Println("Number of subscribers:", signal.Len())
	Len() int

	// IsEmpty checks if the signal has any subscribers.
	//
	// It returns true if the signal has no subscribers, and false otherwise.
	// This can be used to check if there are any listeners before emitting a signal.
	//
	// Example:
	//	signal := signals.New[int]()
	//	fmt.Println("Is signal empty?", signal.IsEmpty()) // Should print true
	//	signal.AddListener(func(ctx context.Context, payload int) {
	//		// Listener implementation
	//		// ...
	//	})
	//	fmt.Println("Is signal empty?", signal.IsEmpty()) // Should print false
	IsEmpty() bool
}

Signal is the interface that represents a signal that can be subscribed to emitting a payload of type T.

func New

func New[T any]() Signal[T]

New creates a new signal that can be used to emit and listen to events asynchronously.

Example:

signal := signals.New[int]()
signal.AddListener(func(ctx context.Context, payload int) {
    // Listener implementation
    // ...
})
signal.Emit(context.Background(), 42)

func NewSync added in v1.1.0

func NewSync[T any]() Signal[T]

NewSync creates a new signal that can be used to emit and listen to events synchronously.

Example:

signal := signals.NewSync[int]()
signal.AddListener(func(ctx context.Context, payload int) {
    // Listener implementation
    // ...
})
signal.Emit(context.Background(), 42)

type SignalListener

type SignalListener[T any] func(context.Context, T)

SignalListener is a type definition for a function that will act as a listener for signals. This function takes two parameters:

  1. A context of type `context.Context`. This is typically used for timeout and cancellation signals, and can carry request-scoped values across API boundaries and between processes.
  2. A payload of generic type `T`. This can be any type, and represents the data or signal that the listener function will process.

The function does not return any value.

type SyncSignal added in v1.1.0

type SyncSignal[T any] struct {
	BaseSignal[T]
}

SyncSignal is a struct that implements the Signal interface. It provides a synchronous way of notifying all subscribers of a signal. The type parameter `T` is a placeholder for any type.

func (*SyncSignal[T]) Emit added in v1.1.0

func (s *SyncSignal[T]) Emit(ctx context.Context, payload T)

Emit notifies all subscribers of the signal and passes the payload in a synchronous way.

The payload is of the same type as the SyncSignal's type parameter `T`. The method iterates over the subscribers slice of the SyncSignal, and for each subscriber, it calls the subscriber's listener function, passing the context and the payload. If the context has a deadline or cancellable property, the listeners must respect it. This means that the listeners should stop processing when the context is cancelled. Unlike the AsyncSignal's Emit method, this method does not call the listeners in separate goroutines, so the listeners are called synchronously, one after the other.

Example:

signal := signals.NewSync[string]()
signal.AddListener(func(ctx context.Context, payload string) {
	// Listener implementation
	// ...
})

signal.Emit(context.Background(), "Hello, world!")

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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