-
Notifications
You must be signed in to change notification settings - Fork 269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] ua: export NodeID fields to make it easier marshallable #250
base: main
Are you sure you want to change the base?
Conversation
for opcua pubsub (Part 14), a consumer needs to store metadata frames. marshalling them as a JSON is a possible solution; which is not possible without custom types if NodeID fields are unexported. With the fields being exported, it's possible to marshal it with default marshaling behavior.
related: #243 |
As always with these kinds of network/byte structs, there are other relationships and meanings baked into the raw values. For example, should the JSON contain the |
I would prefer not to export the fields since they are an implementation detail of how to represent a |
@birdayz unrelated question: are you working on adding PubSub support to gopcua? That would be cool. |
Yes. It's currently internal code but i will will upstream it in the next weeks. |
Regarding the string representation, that is how I did it for our Sub code: https://gist.github.com/kung-foo/b184a432de2e3063f891f96d42b25795#file-monitor-go-L98 |
@birdayz After thinking about this for a bit why doesn't the |
yeah i guess it will work. Anyhow, i would need to add the MarshalJSON / UnmarshalJSON functions to the NodeID type. which is OK. i just didn't see a function to construct a NodeID type from the string when unmarshaling from JSON(so the opposite direction of what String() is doing). Or did i just miss that? |
There should be ParseNodeID |
Looks good. Will update the PR next week :) |
regarding the JSON structure, part 6 of the spec (5.4.2.10) says that the format should be: type JNodeID struct {
IDType int `json:"IdType,omitempty"`
ID interface{} `json:"Id"`
Namespace int `json:",omitempty"`
} |
If we follow down the path of implementing the official JSON mapping via I'm not sure I'd like that since this might a lot of unnecessary casting between A standalone JSON encoder might be a better approach since it provides more flexibility on the format and the Go types we're mapping to. It would hide the complexity of the protocol better. |
I agree that all the casting would be a pain, and probably brittle. On the other hand, the JSON should either match the spec exactly, or this project should explicitly state that the JSON is not compatible. It's a mess either way. |
But a stand-alone encoder func would solve that, wouldn’t it? Instead of MarshalJSON.
|
Do you mean an encoder/decoder that doesn't live on the |
Most of the OPC/UA types have a JSON representation that is compatible with what the Go JSON encoder would generate from the current structs. However, there are some exceptions. For example,
All other numbers should be encoded as JSON numbers. However, special values like
Structs with an So how would we encode/decode a struct that has a
It would be nice if the std JSON encoder had hooks for the standard types which we could replace but it doesn't. I think option 3 could work since it uses the std json encoder and the custom types but hides all that from the user. |
https://play.golang.org/p/7ENGZP7zxkF for option 3 also gives you an idea about the amount of casting and why I'd like to avoid that. Having said that, I think custom |
Thanks for having the discussion. this was also my preferred alternative, I'm happy to work on that. |
@magiconair Would you expose (public) the func (n *NodeID) AsJNodeID() *JNodeID {
return &JNodeID{
Namespace: n.nid, // easy
ID: ... // not easy
...
}
}
func (n *NodeID) MarshalJSON() ([]byte, error) {
return json.Marshal(n.AsJNodeID())
} |
I would hide it for now. If we change our minds we can. Otherwise, the horse is out of the barn and users may get confused which one to use. |
FYI i currently don't have time to pursue this due to time pressure at work for other stuff :] i didn't forget about and am still planning to open source the pubsub impl. and work on this. i hope to pick it up in autumn again. sorry! |
I'm currently working on a OPCUA PubSub (Part 14) implementation. For one step, where the message consumer has to store MetaData persistently, so we can reference it later when a DataFrame arrives, i need to Marshal the MetaData. I chose to do it with JSON. The default JSON Marshaler can't store the NodeID, as its fields are unexported. By exporting them, it's possible to fully marshal the metadata. (Which contains stuff like StuctureDescription).
I'm open for other solutions; one possibility would be implementing MarshalJSON() , UnmarshalJSON() with a custom unexported struct with these exported fields.
Another option is that i implement my own custom data structure; but with so many nested fields it's messy and i will pretty much create a clone of gopcua's structs with a minor difference. Not very good, i would prefer to have it upstream.