From 3c9e154162f97466696ab6cbfa20d87d7bc66613 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Tue, 22 May 2018 19:56:55 +0200 Subject: [PATCH] created 'type checker' using 'plugins' --- checker/public.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++ checker/types.go | 22 +++++++++++ 2 files changed, 118 insertions(+) create mode 100644 checker/public.go create mode 100644 checker/types.go diff --git a/checker/public.go b/checker/public.go new file mode 100644 index 0000000..2d2a3fb --- /dev/null +++ b/checker/public.go @@ -0,0 +1,96 @@ +package checker + +import ( + "fmt" + "plugin" + "strings" +) + +// CreateRegistry creates an empty type registry +// if TRUE is given, it will use default Types +// see ./default_types.go +func CreateRegistry(useDefaultTypes bool) *TypeRegistry { + return &TypeRegistry{ + Types: make([]Type, 0), + } +} + +// Add adds a type to the registry; it must be a +// valid and existing plugin name without the .so extension +func (tr *TypeRegistry) Add(pluginName string) error { + + /* (1) Check plugin name */ + if len(pluginName) < 1 { + return fmt.Errorf("Plugin name must not be empty") + } + + /* (2) Check plugin extension */ + if strings.HasSuffix(pluginName, ".so") { + return fmt.Errorf("Plugin name must be provided without extension: '%s'", pluginName[0:len(pluginName)-3]) + } + + /* (3) Try to load the plugin */ + p, err := plugin.Open(fmt.Sprintf("%s.so", pluginName)) + if err != nil { + return err + } + + /* (4) Export wanted properties */ + matcher, err := p.Lookup("Match") + if err != nil { + return fmt.Errorf("Missing method 'Match()'; %s", err) + } + + checker, err := p.Lookup("Check") + if err != nil { + return fmt.Errorf("Missing method 'Check()'; %s", err) + } + + /* (5) Cast Match+Check */ + matcherCast, ok := matcher.(func(string) bool) + if !ok { + return fmt.Errorf("Match() is malformed") + } + + checkerCast, ok := checker.(func(interface{}) bool) + if !ok { + return fmt.Errorf("Check() is malformed") + } + + /* (6) Add type to registry */ + tr.Types = append(tr.Types, Type{ + Match: matcherCast, + Check: checkerCast, + }) + + return nil +} + +// Checks the 'value' which must be of type 'name' +func (tr TypeRegistry) Run(name string, value interface{}) bool { + + var T *Type = nil + + /* (1) Iterate to find matching type (take first) */ + for _, t := range tr.Types { + + // stop if found + if t.Match(name) { + T = &t + break + } + + // else log + fmt.Printf("does not match\n") + } + + /* (2) Abort if no matching type */ + if T == nil { + return false + } + + /* (3) Check */ + fmt.Printf("Check is %t\n", T.Check(value)) + return T.Check(value) + +} diff --git a/checker/types.go b/checker/types.go new file mode 100644 index 0000000..1969b08 --- /dev/null +++ b/checker/types.go @@ -0,0 +1,22 @@ +package checker + +// Matcher returns whether a type 'name' matches a type +type Matcher func(name string) bool + +// Checker returns whether 'value' is valid to this Type +// note: it is a pointer because it can be formatted by the checker if matches +// to provide indulgent type check if needed +type Checker func(value interface{}) bool + +// Type contains all necessary methods +// for a type provided by user/developer +type Type struct { + Match func(string) bool + Check func(interface{}) bool +} + +// TypeRegistry represents a registry containing all available +// Type-s to be used by the framework according to the configuration +type TypeRegistry struct { + Types []Type // registered Type-s +}