device

package
v0.0.0-...-119448c Latest Latest
Warning

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

Go to latest
Published: Apr 20, 2018 License: MIT Imports: 16 Imported by: 3

Documentation

Overview

Package device provides basic device definition and management.

This package offers a definition of a basic device, D, as well as several implementations of D.

Users wishing to interact with real devices will find better utility in the "discovery" package, which uses this package to instantiate Remote devices for each discovered device.

Mutable is offered to track the pixel state of a given device and generate mutation packets to sync the device to that state.

Snapshot can be used to store a (potentially-sampled) pixel state of a given of device.

Optional Prometheus monitoring can be enabled by registering on startup (generally init()) via RegisterMonitoring.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoRoute = errors.New("no route for device")

ErrNoRoute is a sentinel error that is returned by a Router's Route command when the requested device is not registered.

Functions

func IsDone

func IsDone(d D) bool

IsDone returns true if this device is done (its DoneC is closed).

func RegisterMonitoring

func RegisterMonitoring(reg prometheus.Registerer)

RegisterMonitoring registers all of this package's monitoring metrics.

Types

type D

type D interface {
	// ID is this device's ID. It should be unique (within this system) to this
	// device, and should be consistent between executions, regardless of simple
	// reconfiguations on the device's part.
	//
	// A hardware address is suitable for this purpose.
	ID() string

	// Ordinal returns this Device's ordinal value.
	Ordinal() Ordinal

	// Sender returns a device Sender instance.
	//
	// Multiple Senders can be created for the same device; however, any
	// individual Sender is not safe for concurrent use (see Sender interface
	// for more information).
	//
	// It is the caller's responsibility to close the Sender when finished.
	Sender() (Sender, error)

	// DiscoveryHeaders returns the device's discovery protocol headers.
	//
	// DiscoveryHeaders may return nil if no headers are available.
	//
	// DiscoveryHeaders can be used to obtain a protocol.PacketReader, if packet
	// parsing is required.
	DiscoveryHeaders() *protocol.DiscoveryHeaders

	// DoneC is closed when this D is no longer considered active.
	DoneC() <-chan struct{}

	// Addr is this device's address. It may be nil.
	Addr() net.Addr

	// Info returns the current information and stats for this device.
	Info() Info
}

D is a single device. It implements a generic device interface.

type Info

type Info struct {
	PacketsReceived int64
	BytesReceived   int64

	PacketsSent int64
	BytesSent   int64

	Created  time.Time
	Observed time.Time
}

Info is a set of stats collected for this device.

type Listener

type Listener interface {
	// HandlePacket is called for each Packet sent to this Router.
	//
	// pkt is a shared read-only object, and must not be modified.
	HandlePacket(d D, pkt *protocol.Packet)
}

Listener is registered with a Router, and receives a callback for each routed packet.

func ListenerFunc

func ListenerFunc(fn func(D, *protocol.Packet)) Listener

ListenerFunc generates a Listsner whose HandlePacket method calls the supplied function.

type Local

type Local struct {
	// The local device's ID.
	DeviceID string

	// OnPacketData is wthe callback that is called when new packet data is
	// received.
	//
	// OnPacketData must not be nil.
	//
	// The packet data is owned by a bufferpool.Pool. Recipients of the buffer may
	// Retain it and Release it to prevent it from reentering the pool. The buffer
	// that is handed to the callback is automatically Released when the callback
	// returns; the callback SHOULD NOT release the buffer.
	OnPacketData func(buf *bufferpool.Buffer)

	// UDPPacketPool, if not nil, is the packet pool to use for UDP packet data.
	//
	// If nil, a local packet pool will be generated and used.
	UDPPacketPool *bufferpool.Pool

	// Logger, if not nil, is the logger to use to log events.
	//
	// Changes to Logger after Start is called will have no effect.
	Logger logging.L
	// contains filtered or unexported fields
}

Local is a local "virtual' device. A Local allows your local system to instantiate its own devices. Local can be useful for testing and the simluation of devices.

Local's exported fields must not be changed after Start is called.

func (*Local) Addr

func (d *Local) Addr() net.Addr

Addr implements D.

Addr will always be a *net.UDPAddr.

func (*Local) Close

func (d *Local) Close() error

Close closes the Local, freeing its remote connection resource and marking it Done.

After Close has returned, no more packet callbacks will be sent.

func (*Local) DiscoveryHeaders

func (d *Local) DiscoveryHeaders() *protocol.DiscoveryHeaders

DiscoveryHeaders implements D.

func (*Local) DoneC

func (d *Local) DoneC() <-chan struct{}

DoneC implements D.

func (*Local) ID

func (d *Local) ID() string

ID implements D.

func (*Local) Info

func (d *Local) Info() Info

Info implements D.

func (*Local) Ordinal

func (d *Local) Ordinal() Ordinal

Ordinal implements D.

The Local is not part of any ordinal group.

func (*Local) Sender

func (d *Local) Sender() (Sender, error)

Sender implements D.

func (*Local) Start

func (d *Local) Start(conn *net.UDPConn)

Start finishes device setup and begins listening for packets.

The returned device presumes ownership over conn, and will close it when closed.

func (*Local) String

func (d *Local) String() string

String implements D.

func (*Local) UpdateHeaders

func (d *Local) UpdateHeaders(dh *protocol.DiscoveryHeaders)

UpdateHeaders sets the base discovery headers to use for this device.

These headers will be updated internally to include the local device address information.

UpdateHeaders must be called at least once before DiscoveryHeaders is invoked, ideally at setup.

type Monitoring

type Monitoring struct {
	// contains filtered or unexported fields
}

Monitoring is a thin wrapper around a D that logs monitoring information about that device.

func (*Monitoring) Update

func (md *Monitoring) Update(d D)

Update updates device metrics.

type Mutable

type Mutable struct {
	// contains filtered or unexported fields
}

Mutable wraps a device, D, offering a method of setting and updating its pixel state.

Currently, Mutable is only implemented for PixelPusher devices.

Mutable is not safe for concurrent use; concurrent users must lock around it.

func (*Mutable) ClonePixelsTo

func (m *Mutable) ClonePixelsTo(strip int, target *pixel.Buffer)

ClonePixelsTo clones the contents of the specified pixel strip into target.

If strip references an invalid strip index, nothing will happen, and target will be unmodified.

func (*Mutable) GetPixel

func (m *Mutable) GetPixel(strip, p int) pixel.P

GetPixel returns the value of the specified pixel offset in the specified strip.

If p or strip are out of bounds, a zero-value pixel will be returned.

func (*Mutable) Initialize

func (m *Mutable) Initialize(dh *protocol.DiscoveryHeaders)

Initialize ensures that each strip state matches the state described by the device's discovery headers.

Initialize can be called more than once, and will adjust the current strip and pixel count based on the current set of headers.

func (*Mutable) NumStrips

func (m *Mutable) NumStrips() int

NumStrips returns the number of configured strips.

func (*Mutable) PixelsPerStrip

func (m *Mutable) PixelsPerStrip() int

PixelsPerStrip returns the number of pixels per strip.

func (*Mutable) SetPixel

func (m *Mutable) SetPixel(strip, pixel int, v pixel.P) bool

SetPixel sets the value of the specified pixel in the specified strip to v.

If the pixel exists and was modified, SetPixel will return true and note that it has been mutated.

If index is out of bounds, SetPixel will not change anything and return false.

func (*Mutable) SetPixels

func (m *Mutable) SetPixels(strip int, pixels *pixel.Buffer)

SetPixels sets the full set of pixels for this device to the value in pixels.

If pixels has the same flags and size as m's strip, SetPixels will be a fast buffer clone. Otherwise, pixels will be set pixel-by-pixel within bounds.

If strip is out of bounds, nothing will be updated.

func (*Mutable) SyncPacket

func (m *Mutable) SyncPacket() *protocol.Packet

SyncPacket generates a packet containing an update instruction for each modified strip. All strips will be marked unmodified after sync.

type Ordinal

type Ordinal struct {
	Group      int
	Controller int
}

Ordinal is the device's ordinal value, identifying which logical group it belongs to.

func InvalidOrdinal

func InvalidOrdinal() Ordinal

InvalidOrdinal returns an Ordinal that registers as invalid.

func (*Ordinal) IsValid

func (o *Ordinal) IsValid() bool

IsValid returns true if this is a valid Ordinal. An ordinal is valid if both its Group and Controller are >0.

func (*Ordinal) String

func (o *Ordinal) String() string

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is a generic device registry. It tracks devices by ID, records which group devices belong to, and removes device entries when they expire.

func (*Registry) Add

func (reg *Registry) Add(d D)

Add adds or update's d's registration in the Registry.

func (*Registry) AllGroups

func (reg *Registry) AllGroups() map[int][]D

AllGroups returns all registered groups and their respective devices.

func (*Registry) DevicesForGroup

func (reg *Registry) DevicesForGroup(group int) []D

DevicesForGroup returns the devices for the specified group.

If no devices are registered in that group, it will return an empty slice.

func (*Registry) Get

func (reg *Registry) Get(id string) D

Get returns the registered device for the specified ID.

If no device is registered for this ID, Get will return nil.

func (*Registry) GetUniqueOrdinal

func (reg *Registry) GetUniqueOrdinal(o Ordinal) D

GetUniqueOrdinal returns the registered device for the specified ordinal.

If there is no device that is uniquely registered for o, GetOrdinal will return nil.

type Remote

type Remote struct {
	// Logger, if not nil, is the logger that this device and its supporting
	// constructs will use.
	Logger logging.L
	// contains filtered or unexported fields
}

Remote is a device implementation for a remote PixelPusher device.

Remote is typically backed by a discovered device's headers. In this case, Remote is a fully-functional local stub for that device and its most recent state.

Remote may also be constructed directly as a stub with MakeRemoteStub. In this case, it will not have access to any headers, and is used solely as a local stub to the remote device.

func MakeRemote

func MakeRemote(id string, dh *protocol.DiscoveryHeaders) *Remote

MakeRemote initializes a Remote device instance.

The device must not be used until it has been observed via Observe(), at which point it will become fully active and valid.

func MakeRemoteStub

func MakeRemoteStub(id string, addr *net.UDPAddr) *Remote

MakeRemoteStub constructs a new Remote device without requiring a full set of headers.

MakeRemoteStub can be used to communicate with devices at known addresses.

func (*Remote) Addr

func (d *Remote) Addr() net.Addr

Addr implements D.

func (*Remote) DiscoveryHeaders

func (d *Remote) DiscoveryHeaders() *protocol.DiscoveryHeaders

DiscoveryHeaders implements D.

func (*Remote) DoneC

func (d *Remote) DoneC() <-chan struct{}

DoneC implements D.

func (*Remote) ID

func (d *Remote) ID() string

ID implements D.

func (*Remote) Info

func (d *Remote) Info() (i Info)

Info implements D.

func (*Remote) MarkDone

func (d *Remote) MarkDone()

MarkDone closes this device's done channel, shutting down any observation and marking this device "done" to external users.

MarkDone is safe for concurrent use, and may be called multiple times; however, calls past the first time will do nothing.

func (*Remote) Ordinal

func (d *Remote) Ordinal() Ordinal

Ordinal implements D.

func (*Remote) Sender

func (d *Remote) Sender() (Sender, error)

Sender implements D.

func (*Remote) String

func (d *Remote) String() string

func (*Remote) UpdateHeaders

func (d *Remote) UpdateHeaders(now time.Time, dh *protocol.DiscoveryHeaders)

UpdateHeaders live-updates this device's headers.

This can be used to update an instance of the device that has been observed with a new set of headers (e.g., via discovery).

type Router

type Router struct {
	// Registry is the device registry. It is used to identify devices that will
	// receive routed packets.
	//
	// Registry must not be nil
	Registry *Registry
	// Logger is the logger that this Router should use.
	//
	// Setting or changing Logger should be done during Router setup, and is
	// not safe for concurrent use.
	Logger logging.L
	// contains filtered or unexported fields
}

Router contains a registry of devices. Once registered, a device remains with the Router until it is either removed or marks itself done via DoneC.

A Router accepts a series of packets delivered to a specific device ID, and sends those packets to that device via a PacketWriter.

A Router operates on a device ID's Value field, rather than the full ID, since its targeted at sending recorded data, which will not include the ID's Type parameter.

func (*Router) AddListener

func (r *Router) AddListener(l Listener)

AddListener registers a Listener with this Router.

func (*Router) RemoveListener

func (r *Router) RemoveListener(l Listener)

RemoveListener removes a Listener from this Router.

If l is not registered, nothing will happen.

func (*Router) Route

func (r *Router) Route(ordinal Ordinal, id string, pkt *protocol.Packet) error

Route sends a packet to the device identified by the specified ordinal or id.

If the ordinal is valid and uniquely registered, the device registered to that ordinal will receive the packet. Otherwise, if the device ID is registered, it will receive the packet.

func (*Router) Shutdown

func (r *Router) Shutdown()

Shutdown all routes and resources used by the Router.

type Sender

type Sender interface {
	// DatagramSender sends a raw datagram to the underlying device.
	//
	// Generally, users should prefer to send packets via SendPacket over
	// SendDatagram.
	network.DatagramSender

	// SendPacket writes the contents of packet to the target device.
	//
	// Unlike SendDatagram, SendPacket has the opportunity to examine the content
	// and intent of the packet and determine how to optimally send it to the
	// target device.
	//
	// Regardless of any internal buffering, SendPacket will not retain any of
	// packet.
	SendPacket(packet *protocol.Packet) error
}

Sender is an interface that can dispatch data and packets to a single device.

Sender is not safe for concurrent use.

func MonitorSender

func MonitorSender(d D, s Sender) Sender

MonitorSender wraps a Sender from d in a monitoring shim.

type Snapshot

type Snapshot struct {
	// ID is the snapshot device ID.
	ID string

	// Strips is the set of strips on this device.
	Strips []*pixelpusher.StripState
}

Snapshot represents a snapshot of the device state.

A Snapshot is an independent data clone.

Currently this only supports PixelPusher device states.

type SnapshotManager

type SnapshotManager struct {
	// SampleRate is the snapshot sample rate. After a sample is taken, any
	// further samples will be ignored until SampleRate has passed.
	//
	// If SampleRate is <= 0, all samples will be taken.
	SampleRate time.Duration
	// contains filtered or unexported fields
}

SnapshotManager manages device state snapshots.

TODO: Generalize for more than PixelPusher.

SnapshotManager is safe for concurrent use.

func (*SnapshotManager) Delete

func (m *SnapshotManager) Delete(d D)

Delete removes any stored snapshot state for d.

func (*SnapshotManager) HandlePacket

func (m *SnapshotManager) HandlePacket(d D, pkt *protocol.Packet)

HandlePacket accepts a packet, pkt, and updates its associated strip snapshot based on the packet's contents. If the packet isn't a pixel packet, it will be ignored.

func (*SnapshotManager) HasSnapshotForDevice

func (m *SnapshotManager) HasSnapshotForDevice(d D) bool

HasSnapshotForDevice returns true if a snapshot is stored for d.

func (*SnapshotManager) SnapshotForDevice

func (m *SnapshotManager) SnapshotForDevice(d D) *Snapshot

SnapshotForDevice returns the current snapshot for the specified device.

Jump to

Keyboard shortcuts

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