Skip to content

Commit

Permalink
updates to plugin options and cleanup (#345)
Browse files Browse the repository at this point in the history
  • Loading branch information
edaniszewski committed Mar 30, 2020
1 parent 45a8c40 commit 774b43f
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 522 deletions.
118 changes: 59 additions & 59 deletions sdk/context.go
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
package sdk

// ctx is the global context for the plugin. It stores various plugin settings,
// data, and handler functions for customizable plugin functionality.
var ctx = newPluginContext()
//// ctx is the global context for the plugin. It stores various plugin settings,
//// data, and handler functions for customizable plugin functionality.
//var ctx = newPluginContext()

// PluginContext holds context information for the plugin. Having the context
// global allows simpler access, without having to pass references to the plugin
// through many of our functions.
type PluginContext struct {
// The handler functions that can extend/modify a plugin's behavior.
// These can be set via PluginOptions, or can use a default handler.
deviceIdentifier DeviceIdentifier
dynamicDeviceRegistrar DynamicDeviceRegistrar
dynamicDeviceConfigRegistrar DynamicDeviceConfigRegistrar
deviceDataValidator DeviceDataValidator

// outputTypes is a map where the the key is the name of the output type
// and the value is the corresponding OutputType.
outputTypes map[string]*OutputType

// devices holds all of the known devices configured for the plugin.
devices map[string]*Device

// deviceHandlers holds all of the DeviceHandlers that are registered with the plugin.
deviceHandlers []*DeviceHandler

//// preRunActions holds all of the known plugin actions to run prior to starting
//// up the plugin server and data manager.
//preRunActions []pluginAction

//// postRunActions holds all of the known plugin actions to run after terminating
//// the plugin server and data manager.
//postRunActions []pluginAction

//// deviceSetupActions holds all of the known device device setup actions to run
//// prior to starting up the plugin server and data manager. The map key is the
//// filter used to apply the deviceAction value to a Device instance.
//deviceSetupActions map[string][]deviceAction
}
//// PluginContext holds context information for the plugin. Having the context
//// global allows simpler access, without having to pass references to the plugin
//// through many of our functions.
//type PluginContext struct {
// // The handler functions that can extend/modify a plugin's behavior.
// // These can be set via PluginOptions, or can use a default handler.
// deviceIdentifier DeviceIdentifier
// dynamicDeviceRegistrar DynamicDeviceRegistrar
// dynamicDeviceConfigRegistrar DynamicDeviceConfigRegistrar
// deviceDataValidator DeviceDataValidator
//
// // outputTypes is a map where the the key is the name of the output type
// // and the value is the corresponding OutputType.
// outputTypes map[string]*OutputType
//
// // devices holds all of the known devices configured for the plugin.
// devices map[string]*Device
//
// // deviceHandlers holds all of the DeviceHandlers that are registered with the plugin.
// deviceHandlers []*DeviceHandler
//
// //// preRunActions holds all of the known plugin actions to run prior to starting
// //// up the plugin server and data manager.
// //preRunActions []pluginAction
//
// //// postRunActions holds all of the known plugin actions to run after terminating
// //// the plugin server and data manager.
// //postRunActions []pluginAction
//
// //// deviceSetupActions holds all of the known device device setup actions to run
// //// prior to starting up the plugin server and data manager. The map key is the
// //// filter used to apply the deviceAction value to a Device instance.
// //deviceSetupActions map[string][]deviceAction
//}

//// checkDeviceHandlers checks that the registered device handlers do not have duplicate
//// names. Device handler names should be unique.
Expand All @@ -60,26 +60,26 @@ type PluginContext struct {
// return fmt.Errorf("[sdk] device handler names should be unique, but found duplicates: %v", duplicates)
//}

// newPluginContext creates a new instance of the plugin context, supplying the default
// values for any context fields that have defaults.
func newPluginContext() *PluginContext {
return &PluginContext{
deviceIdentifier: defaultDeviceIdentifier,
dynamicDeviceRegistrar: defaultDynamicDeviceRegistration,
dynamicDeviceConfigRegistrar: defaultDynamicDeviceConfigRegistration,
deviceDataValidator: defaultDeviceDataValidator,

outputTypes: map[string]*OutputType{},
devices: map[string]*Device{},
deviceHandlers: []*DeviceHandler{},
//preRunActions: []pluginAction{},
//postRunActions: []pluginAction{},
//deviceSetupActions: map[string][]deviceAction{},
}
}
//// newPluginContext creates a new instance of the plugin context, supplying the default
//// values for any context fields that have defaults.
//func newPluginContext() *PluginContext {
// return &PluginContext{
// deviceIdentifier: defaultDeviceIdentifier,
// dynamicDeviceRegistrar: defaultDynamicDeviceRegistration,
// dynamicDeviceConfigRegistrar: defaultDynamicDeviceConfigRegistration,
// deviceDataValidator: defaultDeviceDataValidator,
//
// outputTypes: map[string]*OutputType{},
// devices: map[string]*Device{},
// deviceHandlers: []*DeviceHandler{},
// //preRunActions: []pluginAction{},
// //postRunActions: []pluginAction{},
// //deviceSetupActions: map[string][]deviceAction{},
// }
//}

// resetContext is a utility function that is used as a test helper to clear the plugin
// context. This should not be used outside of testing.
func resetContext() { // nolint
ctx = newPluginContext()
}
//// resetContext is a utility function that is used as a test helper to clear the plugin
//// context. This should not be used outside of testing.
//func resetContext() { // nolint
// ctx = newPluginContext()
//}
20 changes: 13 additions & 7 deletions sdk/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,11 @@ func (device *Device) Read() (*ReadContext, error) {
if device == nil {
return nil, fmt.Errorf("device is nil")
}
if device.Handler == nil {
return nil, fmt.Errorf("device.Handler is nil")
if device.handler == nil {
return nil, fmt.Errorf("device.handler is nil")
}
if device.Handler.Read != nil {
readings, err := device.Handler.Read(device)
if device.handler.Read != nil {
readings, err := device.handler.Read(device)
if err != nil {
return nil, err
}
Expand All @@ -302,21 +302,27 @@ func (device *Device) Read() (*ReadContext, error) {
// FIXME: should we update the unsupported command error to be more descriptive?
func (device *Device) Write(data *WriteData) error {
if device.IsWritable() {
return device.Handler.Write(device, data)
return device.handler.Write(device, data)
}
return &errors.UnsupportedCommandError{}
}

// IsReadable checks if the Device is readable based on the presence/absence
// of a Read/BulkRead action defined in its DeviceHandler.
func (device *Device) IsReadable() bool {
return device.Handler.Read != nil || device.Handler.BulkRead != nil || device.Handler.Listen != nil
if device == nil {
return false
}
return device.handler.Read != nil || device.handler.BulkRead != nil || device.handler.Listen != nil
}

// IsWritable checks if the Device is writable based on the presence/absence
// of a Write action defined in its DeviceHandler.
func (device *Device) IsWritable() bool {
return device.Handler.Write != nil
if device == nil {
return false
}
return device.handler.Write != nil
}

// ID generates the deterministic ID for the Device using its config values.
Expand Down
21 changes: 21 additions & 0 deletions sdk/device_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@ func (manager *deviceManager) init() error {
return nil
}

// GetDevice gets a device from the manager by ID.
func (manager *deviceManager) GetDevice(id string) *Device {
device, exists := manager.devices[id]
if !exists {
log.WithFields(log.Fields{
"id": id,
}).Debug("[device manager] device does not exist")
}
return device
}

func (manager *deviceManager) IsDeviceReadable(id string) bool {
device := manager.GetDevice(id)
return device.IsReadable()
}

func (manager *deviceManager) IsDeviceWritable(id string) bool {
device := manager.GetDevice(id)
return device.IsWritable()
}

// AddDevice adds a device to the DeviceManager and makes sure that it
// has a reference to its DeviceHandler.
//
Expand Down
47 changes: 38 additions & 9 deletions sdk/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,67 @@ package sdk
// A PluginOption sets optional configurations or functional capabilities for
// a plugin. This includes things like device identification and device
// registration behaviors.
type PluginOption func(*PluginContext)
type PluginOption func(*Plugin)

// CustomDeviceIdentifier lets you set a custom function for creating a deterministic
// identifier for a device using the config data for the device.
func CustomDeviceIdentifier(identifier DeviceIdentifier) PluginOption {
return func(ctx *PluginContext) {
ctx.deviceIdentifier = identifier
return func(plugin *Plugin) {
plugin.deviceIdentifier = identifier
}
}

// CustomDynamicDeviceRegistration lets you set a custom function for dynamically registering
// Device instances using the data from the "dynamic registration" field in the Plugin config.
func CustomDynamicDeviceRegistration(registrar DynamicDeviceRegistrar) PluginOption {
return func(ctx *PluginContext) {
ctx.dynamicDeviceRegistrar = registrar
return func(plugin *Plugin) {
plugin.dynamicRegistrar = registrar
}
}

// CustomDynamicDeviceConfigRegistration lets you set a custom function for dynamically
// registering DeviceConfig instances using the data from the "dynamic registration" field
// in the Plugin config.
func CustomDynamicDeviceConfigRegistration(registrar DynamicDeviceConfigRegistrar) PluginOption {
return func(ctx *PluginContext) {
ctx.dynamicDeviceConfigRegistrar = registrar
return func(plugin *Plugin) {
plugin.dynamicConfigRegistrar = registrar
}
}

// CustomDeviceDataValidator lets you set a custom function for validating the Data field
// of a device's config. By default, this data is not validated by the SDK, since it is
// plugin-specific.
func CustomDeviceDataValidator(validator DeviceDataValidator) PluginOption {
return func(ctx *PluginContext) {
ctx.deviceDataValidator = validator
return func(plugin *Plugin) {
plugin.deviceDataValidator = validator
}
}

// PluginConfigRequired is a PluginOption which designates that a Plugin should require
// a plugin config and will fail if it does not detect one. By default, a Plugin considers
// them optional and will use a set of default configurations if no config is found.
func PluginConfigRequired() PluginOption {
return func(plugin *Plugin) {
plugin.pluginCfgRequired = true
}
}

// DeviceConfigOptional is a PluginOption which designates that a Plugin should not require
// device configurations to be required, as they are by default. This can be the case when
// a plugin may support dynamic device configuration, so pre-defined device configs may not
// be specified.
func DeviceConfigOptional() PluginOption {
return func(plugin *Plugin) {
plugin.deviceCfgRequired = false
}
}

// DynamicConfigRequired is a PluginOption which designates that a Plugin requires dynamic
// device configuration. By default, dynamic device configuration is optional. This can
// be set if a plugin is designed to only load devices in a dynamic fashion, and not through
// pre-defined config files.
func DynamicConfigRequired() PluginOption {
return func(plugin *Plugin) {
plugin.dynamicCfgRequired = true
}
}
21 changes: 20 additions & 1 deletion sdk/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ type Plugin struct {
preRun []*PluginAction
postRun []*PluginAction

// Options and handlers
deviceIdentifier DeviceIdentifier
dynamicRegistrar DynamicDeviceRegistrar
dynamicConfigRegistrar DynamicDeviceConfigRegistrar
deviceDataValidator DeviceDataValidator

pluginCfgRequired bool
deviceCfgRequired bool
dynamicCfgRequired bool

// Plugin components
stateManager *StateManager
deviceManager *deviceManager
Expand Down Expand Up @@ -83,14 +93,23 @@ func NewPlugin(options ...PluginOption) (*Plugin, error) {
version: version,
config: conf,

pluginCfgRequired: false,
deviceCfgRequired: true,
dynamicCfgRequired: false,

deviceIdentifier: defaultDeviceIdentifier,
dynamicRegistrar: defaultDynamicDeviceRegistration,
dynamicConfigRegistrar: defaultDynamicDeviceConfigRegistration,
deviceDataValidator: defaultDeviceDataValidator,

stateManager: stateManager,
deviceManager: deviceManager,
server: server,
}

// Set custom options for the plugin.
for _, option := range options {
option(ctx)
option(&p)
}
return &p, nil
}
Expand Down
Loading

0 comments on commit 774b43f

Please sign in to comment.