Documentation ¶
Overview ¶
Different implementations of the node.Node interface either forming the building blocks of your management implemetations or usable as-is for utility functions.
Index ¶
- Constants
- func Diff(a, b node.Node) node.Node
- func Dump(n node.Node, out io.Writer) node.Node
- func DumpBin(out io.Writer) node.Node
- func Dumpf(n node.Node, fname string) node.Node
- func GetFieldName(parent reflect.Value, in string) string
- func JsonContainerReader(container map[string]interface{}) node.Node
- func JsonListReader(list []interface{}) node.Node
- func MetaNameToFieldName(in string) string
- func Null() node.Node
- func OnSave(orig node.Selection, onSave func(*node.Selection) error) (node.Node, error)
- func ReadField(m meta.Leafable, ptrVal reflect.Value) (val.Value, error)
- func ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value) (v val.Value, err error)
- func ReadJSON(data string) node.Node
- func ReadJSONIO(rdr io.Reader) node.Node
- func ReadJSONValues(values map[string]interface{}) node.Node
- func ReflectChild(obj interface{}) node.Node
- func ReflectList(obj interface{}) node.Node
- func Schema(yangModule *meta.Module, yourModule *meta.Module) *node.Browser
- func Trace(target node.Node, out io.Writer) node.Node
- func WriteField(m meta.Leafable, ptrVal reflect.Value, v val.Value) error
- func WriteFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value, v val.Value) error
- func WriteJSON(s *node.Selection) (string, error)
- func WritePrettyJSON(s *node.Selection) (string, error)
- type Basic
- func (s *Basic) Action(r node.ActionRequest) (output node.Node, err error)
- func (s *Basic) BeginEdit(r node.NodeRequest) error
- func (s *Basic) Child(r node.ChildRequest) (node.Node, error)
- func (s *Basic) Choose(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)
- func (s *Basic) Context(sel *node.Selection) context.Context
- func (s *Basic) EndEdit(r node.NodeRequest) error
- func (s *Basic) Field(r node.FieldRequest, hnd *node.ValueHandle) error
- func (n *Basic) Next(r node.ListRequest) (node.Node, []val.Value, error)
- func (s *Basic) Notify(r node.NotifyRequest) (node.NotifyCloser, error)
- func (s *Basic) Peek(sel *node.Selection, consumer interface{}) interface{}
- func (s *Basic) Release(sel *node.Selection)
- type BasicNextItem
- type ConfigProxy
- type CopyOnWrite
- type Extend
- func (e *Extend) Action(r node.ActionRequest) (output node.Node, err error)
- func (e *Extend) BeginEdit(r node.NodeRequest) error
- func (e *Extend) Child(r node.ChildRequest) (node.Node, error)
- func (e *Extend) Choose(sel *node.Selection, choice *meta.Choice) (*meta.ChoiceCase, error)
- func (e *Extend) Context(sel *node.Selection) context.Context
- func (e *Extend) EndEdit(r node.NodeRequest) error
- func (e *Extend) Extend(n node.Node) node.Node
- func (e *Extend) Field(r node.FieldRequest, hnd *node.ValueHandle) error
- func (e *Extend) Next(r node.ListRequest) (child node.Node, key []val.Value, err error)
- func (e *Extend) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)
- func (e *Extend) Peek(sel *node.Selection, consumer interface{}) interface{}
- func (e *Extend) Release(sel *node.Selection)
- type JSONRdr
- type JSONWtr
- type OnListValueChange
- type OnReflectChild
- type OnReflectList
- type Pipe
- type Reflect
- func (self Reflect) Child(v reflect.Value) node.Node
- func (self Reflect) List(o interface{}) node.Node
- func (self Reflect) Object(obj interface{}) node.Node
- func (self Reflect) ReadField(m meta.Leafable, ptrVal reflect.Value) (val.Value, error)
- func (self Reflect) ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value) (val.Value, error)
- func (self Reflect) ReflectList(v reflect.Value, onUpdate OnListValueChange) node.Node
- func (self Reflect) WriteField(m meta.Leafable, ptrVal reflect.Value, v val.Value) error
- func (self Reflect) WriteFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value, v val.Value) error
- type ReflectField
- type ReflectFieldSelector
- type ReflectOnRead
- type ReflectOnWrite
- type Subscription
- type Tee
- func (self Tee) Action(r node.ActionRequest) (output node.Node, err error)
- func (self Tee) BeginEdit(r node.NodeRequest) (err error)
- func (self Tee) Child(r node.ChildRequest) (node.Node, error)
- func (self Tee) Choose(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)
- func (self Tee) Context(s *node.Selection) context.Context
- func (self Tee) EndEdit(r node.NodeRequest) (err error)
- func (self Tee) Field(r node.FieldRequest, hnd *node.ValueHandle) (err error)
- func (self Tee) Next(r node.ListRequest) (node.Node, []val.Value, error)
- func (self Tee) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)
- func (self Tee) Peek(sel *node.Selection, consumer interface{}) interface{}
- func (self Tee) Release(sel *node.Selection)
Examples ¶
Constants ¶
const ( PipeSelect tok = iota + 1 PipeListItem PipeLeaf PipeEnd )
const QUOTE = '"'
Variables ¶
This section is empty.
Functions ¶
func Diff ¶
Diff compares two nodeutil and returns only the difference. Use Selection constraints to control what is compared and how deep.
func Dump ¶
Dump will send useful information to writer while delegating reads/writes to the given node
func Dumpf ¶
Dumpf will send useful information to file while delegating reads/writes to the given node
func GetFieldName ¶
GetFieldName determines the Go fieldname of a struct field based on the YANG name It first checks if the exact name matches, then uses the MetaNameToFieldName() method to convert YANG names into a go-valid form and finally checks for a struct field with a JSON tag which name matches the YANG name.
func JsonContainerReader ¶
func JsonListReader ¶
func MetaNameToFieldName ¶
func Null ¶
Null throws all data away when written to and always returns itself for reading, no data for fields
func ReadFieldWithFieldName ¶
func ReadJSON ¶
Example ¶
model := ` list bird { key "name"; leaf name { type string; } leaf wingSpan { type int32; } } container location { leaf continent { type enumeration { enum northAmerica; enum southAmerica; enum africa; enum antartica; enum europe; enum austrailia; enum asia; } } } ` myApp := make(map[string]interface{}) sel := exampleSelection(model, nodeutil.ReflectChild(myApp)) data := `{ "bird" : [{ "name": "swallow", "wingSpan" : 10 }], "ignored" : "because it's not in model", "location" : { "continent" : "africa" } } ` if err := sel.InsertFrom(nodeutil.ReadJSON(data)); err != nil { fmt.Print(err.Error()) } out, _ := nodeutil.WriteJSON(sel) fmt.Printf(out)
Output: {"bird":[{"name":"swallow","wingSpan":10}],"location":{"continent":"africa"}}
func ReadJSONValues ¶
func ReflectChild ¶
func ReflectList ¶
func Schema ¶
*
- Schema is used to browse YANG models. If resolve is true all references like
- groupings, uses typedefs are resolved, otherwise they are not.
func Trace ¶
Trace will record all calls and data into a target node and recursively wrap each level to effectively trace all operations on a node and it's children
func WriteField ¶
///////////////
func WriteFieldWithFieldName ¶
Types ¶
type Basic ¶
type Basic struct { // What to return on calls to Peek(). Peek let's you return underlying objects // behind a node and frankly breaks encapsulation so you need not set anything here Peekable interface{} // Only if node is a list. Return a second data structure that breaks down each request // that can be make on each item in a list. // // If you impement this, you should not implement OnNext OnNextItem func(r node.ListRequest) BasicNextItem // Only if node is a list AND you don't implement OnNextItem // // If you impement this, you should not implement OnNextItem OnNext func(r node.ListRequest) (next node.Node, key []val.Value, err error) // Only if there are other containers or lists defined OnChild func(r node.ChildRequest) (child node.Node, err error) // Only if you have leafs defined OnField func(node.FieldRequest, *node.ValueHandle) error // Only if there one or more 'choice' definitions on a list or container and data is used // on a reading mode OnChoose func(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error) // Only if there is one or more 'rpc' or 'action' defined in a model that could be // called. OnAction func(node.ActionRequest) (output node.Node, err error) // Only if there is one or more 'notification' defined in a model that could be subscribed to OnNotify func(r node.NotifyRequest) (node.NotifyCloser, error) // Peekable is often enough, but this always you to return an object dynamically OnPeek func(sel *node.Selection, consumer interface{}) interface{} // OnContext default implementation does nothing OnContext func(s *node.Selection) context.Context // OnBeginEdit default implementation does nothing OnBeginEdit func(r node.NodeRequest) error // OnEndEdit default implementation does nothing OnEndEdit func(r node.NodeRequest) error // OnRelease default implementation does nothing OnRelease func(s *node.Selection) }
Basic stubs every method of node.Node interface so you only have to supply the functions for operations your data node needs to support.
Example (OnAction) ¶
OnActions you just decode the input and encode the output and return it as response.
package main import ( "fmt" "github.com/freeconf/yang/node" "github.com/freeconf/yang/nodeutil" "github.com/freeconf/yang/parser" ) func main() { // YANG 1.1 - 'rpc' is same as 'action' but only used at the top-level of a // module for backward compatibility with YANG 1.0 model := ` rpc sum { input { leaf a { type int32; } leaf b { type int32; } } output { leaf result { type int32; } } }` // Data data := &nodeutil.Basic{ OnAction: func(r node.ActionRequest) (out node.Node, err error) { switch r.Meta.Ident() { case "sum": var n nums if err := r.Input.InsertInto(nodeutil.ReflectChild(&n)); err != nil { return nil, err } result := map[string]interface{}{ "result": n.Sum(), } return nodeutil.ReflectChild(result), nil } return }, } sel, err := exampleSelection(model, data).Find("sum") if err != nil { panic(err) } // JSON is a useful format to use as input, but this can come from any node // that would return "a" and "b" leaves. result, err := sel.Action(nodeutil.ReadJSON(`{"a":10,"b":32}`)) if err != nil { panic(err) } examplePrint(result) } type nums struct { A int B int } func (n nums) Sum() int { return n.A + n.B } func examplePrint(sel *node.Selection) { s, err := nodeutil.WriteJSON(sel) if err != nil { panic(err) } fmt.Println(s) } func exampleSelection(yangFragment string, n node.Node) *node.Selection { mstr := fmt.Sprintf(`module x { namespace ""; prefix ""; revision 0; %s }`, yangFragment) model, err := parser.LoadModuleFromString(nil, mstr) if err != nil { panic(err.Error()) } brwsr := node.NewBrowser(model, n) return brwsr.Root() }
Output: {"result":42}
Example (OnChild) ¶
TestReadingStruct expands on TestSimplestExample by wrapping a 'container' around the message. Containers are like a Golang struct.
package main import ( "fmt" "github.com/freeconf/yang/node" "github.com/freeconf/yang/nodeutil" "github.com/freeconf/yang/parser" ) type foo struct { Bar string } func main() { model := ` container foo { leaf bar { type string; } } ` f := &foo{ Bar: "x", } data := &nodeutil.Basic{ OnChild: func(r node.ChildRequest) (node.Node, error) { switch r.Meta.Ident() { case "foo": if r.New { f = &foo{} } else if r.Delete { f = nil } if f != nil { return nodeutil.ReflectChild(f), nil } } return nil, nil }, } sel := exampleSelection(model, data) fmt.Println("Reading") examplePrint(sel) fmt.Println("Deleting") selFoo, err := sel.Find("foo") if err != nil { panic(err) } if err = selFoo.Delete(); err != nil { panic(err) } examplePrint(sel) fmt.Println("Creating") sel.InsertFrom(nodeutil.ReadJSON(`{"foo":{"bar":"y"}}`)) examplePrint(sel) } func examplePrint(sel *node.Selection) { s, err := nodeutil.WriteJSON(sel) if err != nil { panic(err) } fmt.Println(s) } func exampleSelection(yangFragment string, n node.Node) *node.Selection { mstr := fmt.Sprintf(`module x { namespace ""; prefix ""; revision 0; %s }`, yangFragment) model, err := parser.LoadModuleFromString(nil, mstr) if err != nil { panic(err.Error()) } brwsr := node.NewBrowser(model, n) return brwsr.Root() }
Output: Reading {"foo":{"bar":"x"}} Deleting {} Creating {"foo":{"bar":"y"}}
Example (OnField) ¶
Example defines a model with a single string called "message" as it's only allowed field (or 'leaf').
Models can be matched to a data for lot's of things including reading data, so we create a simple data source that always returns hello.
Models and Data come together as a browser. A browser is all you need to do anything with the data that confirms to the model.
package main import ( "fmt" "github.com/freeconf/yang/node" "github.com/freeconf/yang/nodeutil" "github.com/freeconf/yang/parser" "github.com/freeconf/yang/val" ) func main() { model := ` leaf foo { type string; }` data := &nodeutil.Basic{ // Custom implementations of reading and writing fields called "leafs" or // "leaf-lists" in YANG. OnField: func(r node.FieldRequest, hnd *node.ValueHandle) error { switch r.Meta.Ident() { case "foo": if r.Write { fmt.Println(hnd.Val.String()) } else { hnd.Val = val.String("READ") } } return nil }, } sel := exampleSelection(model, data) examplePrint(sel) sel.UpsertFrom(nodeutil.ReadJSON(`{"foo":"WRITE"}`)) } func examplePrint(sel *node.Selection) { s, err := nodeutil.WriteJSON(sel) if err != nil { panic(err) } fmt.Println(s) } func exampleSelection(yangFragment string, n node.Node) *node.Selection { mstr := fmt.Sprintf(`module x { namespace ""; prefix ""; revision 0; %s }`, yangFragment) model, err := parser.LoadModuleFromString(nil, mstr) if err != nil { panic(err.Error()) } brwsr := node.NewBrowser(model, n) return brwsr.Root() }
Output: {"foo":"READ"} WRITE
Example (OnNext) ¶
ExampleBasic_onNext We need to handle adding, removing and naviagtion thru a list both by key and sequentially. Because most lists have a key, Go's map is often most useful structure to store lists. node.Index helps navigating thru a map sequentally but you can use your own method.
package main import ( "fmt" "github.com/freeconf/yang/node" "github.com/freeconf/yang/nodeutil" "github.com/freeconf/yang/parser" "github.com/freeconf/yang/val" ) type foo struct { Bar string } func main() { model := ` list foo { key "bar"; leaf bar { type string; } }` // Data m := map[string]*foo{ "a": {Bar: "a"}, } dataList := func() node.Node { // helps navigate a map sequentially i := node.NewIndex(m) return &nodeutil.Basic{ OnNextItem: func(r node.ListRequest) nodeutil.BasicNextItem { var f *foo return nodeutil.BasicNextItem{ New: func() error { f = &foo{} m[r.Key[0].String()] = f return nil }, GetByKey: func() error { f = m[r.Key[0].String()] return nil }, GetByRow: func() ([]val.Value, error) { v := i.NextKey(r.Row) if v == node.NO_VALUE { return nil, nil } id := v.String() f = m[id] return []val.Value{val.String(id)}, nil }, DeleteByKey: func() error { delete(m, r.Key[0].String()) return nil }, Node: func() (node.Node, error) { if f != nil { return nodeutil.ReflectChild(f), nil } return nil, nil }, } }, } } sel := exampleSelection(model, &nodeutil.Basic{ OnChild: func(r node.ChildRequest) (node.Node, error) { return dataList(), nil }, }) fmt.Println("Reading") examplePrint(sel) fmt.Println("Deleting") aSel, err := sel.Find("foo=a") if err != nil || aSel == nil { panic(err) } aSel.Delete() examplePrint(sel) fmt.Println("Creating") err = sel.UpsertFrom(nodeutil.ReadJSON(`{"foo":[{"bar":"b"}]}`)) if err != nil { panic(err) } examplePrint(sel) } func examplePrint(sel *node.Selection) { s, err := nodeutil.WriteJSON(sel) if err != nil { panic(err) } fmt.Println(s) } func exampleSelection(yangFragment string, n node.Node) *node.Selection { mstr := fmt.Sprintf(`module x { namespace ""; prefix ""; revision 0; %s }`, yangFragment) model, err := parser.LoadModuleFromString(nil, mstr) if err != nil { panic(err.Error()) } brwsr := node.NewBrowser(model, n) return brwsr.Root() }
Output: Reading {"foo":[{"bar":"a"}]} Deleting {"foo":[]} Creating {"foo":[{"bar":"b"}]}
func (*Basic) Field ¶
func (s *Basic) Field(r node.FieldRequest, hnd *node.ValueHandle) error
func (*Basic) Notify ¶
func (s *Basic) Notify(r node.NotifyRequest) (node.NotifyCloser, error)
type BasicNextItem ¶
type BasicNextItem struct { // New when requested to create a new list item. If you want to wait until all // fields are set before adding new item to list, then you can do that in OnEndEdit New func() error // Find item in list by it's key(s). You will return found item in Node implementation GetByKey func() error // Find item in list by it's row position in list. You will return found item in Node implementation GetByRow func() ([]val.Value, error) // Find item in list by it's row position in list. You will return found item in Node implementation Node func() (node.Node, error) // Remove item. OnEndEdit will also be called if you want to finalize the delete DeleteByKey func() error }
BasicNextItem is used to organize the function calls around individual list items and is returned from Basic.NextItem. You must implement all functions except DeleteByKey and New if list is not editable
type ConfigProxy ¶
type ConfigProxy struct { }
Proxy all but config prremoteties to a delegate node. For the config read prremoteties simply return local copy, for config writes send a copy to far end and if returns ok then trigger storage to save.
type CopyOnWrite ¶
type CopyOnWrite struct { }
type Extend ¶
type Extend struct { Base node.Node OnNext func(parent node.Node, r node.ListRequest) (next node.Node, key []val.Value, err error) OnChild func(parent node.Node, r node.ChildRequest) (child node.Node, err error) OnField func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error OnChoose func(parent node.Node, sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error) OnAction func(parent node.Node, r node.ActionRequest) (output node.Node, err error) OnNotify func(parent node.Node, r node.NotifyRequest) (closer node.NotifyCloser, err error) OnExtend func(e *Extend, sel *node.Selection, m meta.HasDefinitions, child node.Node) (node.Node, error) OnPeek func(parent node.Node, sel *node.Selection, consumer interface{}) interface{} OnBeginEdit func(parent node.Node, r node.NodeRequest) error OnEndEdit func(parent node.Node, r node.NodeRequest) error OnContext func(parent node.Node, s *node.Selection) context.Context OnRelease func(parent node.Node, s *node.Selection) }
Extend let's you alter any Node behavior including the nodeutil it creates.
Example ¶
model := ` leaf bar { type string; } leaf bleep { type string; } ` f := foo{ Bar: "x", } bleep := "y" data := &nodeutil.Extend{ Base: nodeutil.ReflectChild(&f), OnField: func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error { switch r.Meta.Ident() { case "bleep": if r.Write { bleep = hnd.Val.String() } else { hnd.Val = val.String(bleep) } default: return parent.Field(r, hnd) } return nil }, } sel := exampleSelection(model, data) examplePrint(sel)
Output: {"bar":"x","bleep":"y"}
func (*Extend) Field ¶
func (e *Extend) Field(r node.FieldRequest, hnd *node.ValueHandle) error
func (*Extend) Notify ¶
func (e *Extend) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)
type JSONWtr ¶
type JSONWtr struct { // stream to write contents. contents will be flushed only at end of operation Out io.Writer // adds extra indenting and line feeds Pretty bool // otherwise enumerations are written as their labels. it may be // useful to know that json reader can accept labels or values EnumAsIds bool // Namespaces pollute JSON with module name similar to XML namespaces // rules // { "ns:key" : {...}} // where you add the module name to top-level object then qualify any // sub objects when the module changes. Not only does it make JSON even more // illegible, it means you cannot move common meta to a common yang module w/o // altering your resulting JSON. #IETF-FAIL #rant // // See https://datatracker.ietf.org/doc/html/rfc7951 // // I realize this is to protect against 2 or more keys in same line from different // modules but maybe if someone is insane enough to do that, then, and only then, do // you distinguish each key with ns // // To disable this, make this true and get simple JSON like this // // { "key": {...}} QualifyNamespace bool // contains filtered or unexported fields }
func NewJSONWtr ¶
type OnListValueChange ¶
type Reflect ¶
type Reflect struct { // Reflect will use Reflect by default for child node. To override that, implement // this function OnChild OnReflectChild // Reflect will use Reflect by default for list node. To override that, implement // this function OnList OnReflectList // Override the conversion of reading and writing values using reflection OnField []ReflectField }
Uses reflection to marshal data into go structs or maps. Structs fields need to be Public and names must match yang. Map keys must match yang as well.
Has limited ability to provide customer handing of data but you are encouraged to use this combination:
&nodeutil.Extend{ Base: nodeutil.Reflect{}.Object(obj), OnChild:... }
Example (Extend) ¶
model := ` leaf-list bleep { type string; } leaf len { type int32; config false; } ` data := struct { Bleep []string }{ Bleep: []string{ "a", "b", }, } n := &nodeutil.Extend{ Base: nodeutil.ReflectChild(&data), OnField: func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error { switch r.Meta.Ident() { case "len": hnd.Val = val.Int32(len(data.Bleep)) default: return parent.Field(r, hnd) } return nil }, } sel := exampleSelection(model, n) examplePrint(sel)
Output: {"bleep":["a","b"],"len":2}
Example (Struct) ¶
model := ` container foo { leaf bar { type string; } } list foos { key "bar"; leaf bar { type string; } } leaf-list bleep { type string; } ` data := struct { Foo *foo Foos map[string]*foo Bleep []string }{ Foo: &foo{ Bar: "x", }, Foos: map[string]*foo{ "y": { Bar: "y", }, }, Bleep: []string{ "a", "b", }, } sel := exampleSelection(model, nodeutil.ReflectChild(&data)) examplePrint(sel)
Output: {"foo":{"bar":"x"},"foos":[{"bar":"y"}],"bleep":["a","b"]}
func (Reflect) ReadFieldWithFieldName ¶
func (Reflect) ReflectList ¶
func (Reflect) WriteField ¶
type ReflectField ¶
type ReflectField struct { // Select when a field handling is used // This might be called with an invalid fieldElem, so if it depends on this parameters it has to check. When ReflectFieldSelector // Called just after reading the value using reflection to convert value // to freeconf value type. Null means use default conversion // This might be called with an invalid fieldElem, so if it depends on this parameters it has to check. OnRead ReflectOnRead // Called just before setting the value using reflection to convert value // to native type. Null means use default conversion // This might be called with an invalid fieldElem, so if it depends on this parameters it has to check. OnWrite ReflectOnWrite }
ReflectField
type ReflectFieldSelector ¶
type ReflectFieldSelector func(m meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value) bool
ReflectFieldSelector is a predicate to decide which fields are selected for custom handling.
func ReflectFieldByType ¶
func ReflectFieldByType(target reflect.Type) ReflectFieldSelector
ReflectFieldByType is convienent field selection by Go data type. Example:
nodeutil.ReflectFieldByType(reflect.TypeOf(netip.Addr{}))
type ReflectOnRead ¶
type ReflectOnRead func(leaf meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value) (val.Value, error)
ReflectOnRead converts native value to freeconf value Example: time.Duration to int of secs:
func(m meta.Leafable, fieldname string, elem reflect.Value) (val.Value, error) { secs := elem.FieldByName(fieldname).Int() return val.Int32(secs / int64(time.Second)), nil }
type ReflectOnWrite ¶
type ReflectOnWrite func(leaf meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value, v val.Value) error
ReflectOnWrite converts freeconf value to native value. Example: secs as int to time.Duration:
func(_ meta.Leafable, v val.Value) (reflect.Value, error) { return reflect.ValueOf(time.Second * time.Duration(v.Value().(int))), nil },
type Subscription ¶
type Subscription interface {
Close() error
}
Subscription is handle into a list.List that when closed will automatically remove item from list. Useful for maintaining a set of listeners that can easily remove themselves.
Example ¶
listeners := list.New() listener := func() {} sub := NewSubscription(listeners, listeners.PushBack(listener)) fmt.Printf("%d listeners before close\n", listeners.Len()) sub.Close() fmt.Printf("%d listeners after close\n", listeners.Len())
Output: 1 listeners before close 0 listeners after close
func NewSubscription ¶
func NewSubscription(l *list.List, e *list.Element) Subscription
NewSubscription is used by subscription managers to give a token to caller the can close to unsubscribe to events
type Tee ¶
when writing values, splits output into two nodeutil. when reading, reads from secondary only when primary returns nil
func (Tee) Field ¶
func (self Tee) Field(r node.FieldRequest, hnd *node.ValueHandle) (err error)
func (Tee) Notify ¶
func (self Tee) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)