Git Product home page Git Product logo

Comments (15)

dhubler avatar dhubler commented on July 28, 2024

Only the most obvious conversions are in the defaults but you are supposed to create your own Node implementations that implement node.Node and then use strategy like nodeutil.Extend to base all your custom Nodes on

https://github.com/freeconf/yang/blob/master/nodeutil/extend.go

type YourBaseNode struct {
...
}

func (b *YourBaseNode) OnField(..) {
switch r.Meta().Type().Ident() {
case "Addr":
// custom impl

Then use YourBaseNode much like nodeutil.Extend is used.
https://github.com/freeconf/examples/blob/master/basics/mgmt.go#L19

Having said all this, if there is a 100% no brainer to put as default...

from yang.

HRogge avatar HRogge commented on July 28, 2024

I think my main issue is that the Node-Interface for maps contains too much magic, especially with Next/OnNext and Child/OnChild. It takes hours of browsing through the source (especiall nodeutil.reflect) to understand what you are supposed to do with these interface calls.

Most likely the main issue for me is that the map I am trying to connect to restconf doesn't contain pointers, it contains references. Which should be fine for read only access (writing would need more custom code), but I think nodeutil.ReflectChild() cannot handle this kind of map at all. Which means you have to do most of the Node-calls by hand and there is not enough example code how to do it.

from yang.

dhubler avatar dhubler commented on July 28, 2024

from yang.

HRogge avatar HRogge commented on July 28, 2024

I think a great start would be to extend the "car" example with a custom "map" implementation... it already has a array/slice one, but the map one is quite different.

from yang.

HRogge avatar HRogge commented on July 28, 2024

Would you think about applying the following change? It would at least (as far as I can tell) allow read access to all Objects in Go that support the fmt.Stringer interface.

diff --git a/nodeutil/reflect.go b/nodeutil/reflect.go
index 512945c..8292adc 100644
--- a/nodeutil/reflect.go
+++ b/nodeutil/reflect.go
@@ -490,8 +490,13 @@ func ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Va
                fieldVal = fieldVal.Slice(0, fieldVal.Len())
        }
 
+       innerFieldVal := fieldVal.Interface()
        switch dt.Format() {
        case val.FmtString:
+               stringer, ok := innerFieldVal.(fmt.Stringer)
+               if ok {
+                       return val.String(stringer.String()), nil
+               }
                s := fieldVal.String()
                if len(s) == 0 {
                        return nil, nil

from yang.

dhubler avatar dhubler commented on July 28, 2024

Verified this already works
https://github.com/freeconf/yang/blob/master/nodeutil/reflect_test.go#L236

from yang.

HRogge avatar HRogge commented on July 28, 2024

Doesn't work for me...

I use a struct with netip.Prefix elements... when I switch off the patch above, I have to overwrite the nodeutil.ReflectChild behavior, otherwise I get this (overwritten for originator, not for destination).

{"destination":"\u003cnetip.Prefix Value\u003e","originator":"2.3.4.5"}

Maybe this happens because netip.Prefix is a struct, not a native type? If you think it would help, I can write up a small selfcontained test that demonstrates this.

from yang.

HRogge avatar HRogge commented on July 28, 2024

I got my patch for nodeutil/reflect.go even simpler... it seems fmt.Sprint() handles conversion to strings better than "Value.String()".

diff --git a/nodeutil/reflect.go b/nodeutil/reflect.go
index 512945c..71ce106 100644
--- a/nodeutil/reflect.go
+++ b/nodeutil/reflect.go
@@ -492,7 +492,7 @@ func ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Va
 
        switch dt.Format() {
        case val.FmtString:
-               s := fieldVal.String()
+               s := fmt.Sprint(fieldVal.Interface())
                if len(s) == 0 {
                        return nil, nil
                }

This gives me the proper output for netip.Prefix in a struct.

from yang.

dhubler avatar dhubler commented on July 28, 2024

from yang.

HRogge avatar HRogge commented on July 28, 2024

Okay, I tried to boil the test down a bit...

func main() {
	yangPath := source.Path("./cmd/restconf/yang")

	type TestContainer struct {
		Destination netip.Prefix
		Originator  netip.Addr
	}
	type TestData struct {
		Root *TestContainer
	}

	td := TestData{
		Root: &TestContainer{
			Destination: netip.MustParsePrefix("10.0.0.0/8"),
			Originator:  netip.MustParseAddr("192.168.1.1"),
		},
	}
	d := device.New(yangPath)
	if err := d.Add("simple", nodeutil.ReflectChild(&td)); err != nil {
		panic(err)
	}

	srv := restconf.NewServer(d)
	defer srv.Close()

	err := d.ApplyStartupConfig(strings.NewReader(`
		{
			"fc-restconf" : {
				"web": {
					"port" : ":9080"
				},
				"debug" : true
			}
		}`))
	if err != nil {
		return
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	<-c
}
module simple {
    namespace "de.fraunhofer.fkie/kom/rhn/simple";
    prefix "simple";

    description "test yang tree";
    revision 0;

    container root {
        leaf destination {
            type string;
        }
        leaf originator {
            type string;
        }
    }
}

Without my patch the http call http://127.0.0.1:9080/restconf/data/simple:root gives me
{"destination":"\u003cnetip.Prefix Value\u003e","originator":"\u003cnetip.Addr Value\u003e"}

with my patch it gives me
{"destination":"10.0.0.0/8","originator":"192.168.1.1"}

I hope this will help to track down the problem. Most likely the test can be condensed even more, but I still having trouble with parts of freeconf's API.

from yang.

HRogge avatar HRogge commented on July 28, 2024

After looking through the go reflection API for a bit I came up with this patch, which should not slow down normal strings:

diff --git a/nodeutil/reflect.go b/nodeutil/reflect.go
index 512945c..8c0c5b6 100644
--- a/nodeutil/reflect.go
+++ b/nodeutil/reflect.go
@@ -492,7 +492,12 @@ func ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Va
 
        switch dt.Format() {
        case val.FmtString:
-               s := fieldVal.String()
+               var s string
+               if fieldVal.Type().Kind() == reflect.String {
+                       s = fieldVal.String()
+               } else {
+                       s = fmt.Sprint(fieldVal.Interface())
+               }
                if len(s) == 0 {
                        return nil, nil
                }

The problem is in fieldVal.String() call... it calls a subfunction called stringNonString() for something not "Kind == string", which leads to the bad output.

from yang.

dhubler avatar dhubler commented on July 28, 2024

from yang.

HRogge avatar HRogge commented on July 28, 2024

netip.Prefix and netip.Addr is part of Go 1.18 or later

(edit)

func (p Prefix) String() string { ... }
func (ip Addr) String() string { ... }

from yang.

dhubler avatar dhubler commented on July 28, 2024

from yang.

HRogge avatar HRogge commented on July 28, 2024

thank you for accepting the change, I will update my local repository.

I know that this doesn't help with writing, but I have a few other ideas how to extend Freeconf/Yang a bit to make it easier for everyone to hook in data structures without doing a full custom handler. But I first want to look at the "low hanging fruits"... and in my case, I don't need write access... I am using Restconf as a powerful "query"-language to probe the internal data of a routing agent, so large parts (not all) of my data is read-only anyways.

Being able to handle more datatypes out of the box should be good for all users. But next time I find an example about something that doesn't work and how to fix it I will try to include a selfcontained example into my first post in the issue.

from yang.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.