Skip to content
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

Support Metadata frames in PubSub #1518

Merged
merged 74 commits into from
Sep 28, 2021
Merged

Conversation

mrsuciu
Copy link
Contributor

@mrsuciu mrsuciu commented Sep 17, 2021

Implemented changes:

  • Refactored WriterGroupPublishState out of IPubSubConnection file
  • JSON Discovery messages for DataSetMetaData
  • UADP Discovery messages for DataSetMetaData (Request + response)
  • Refactored the UaPublisher, extracted IntervalRunner and reused it in UdpDiscoveryPublisher & UdpDiscoverySubscriber
  • Proposal: automatic setting of ConfigurationVersion based on the rules in 6.2.2.1.5 (part 14)in new class Opc.Ua.PubSub.Configuration.ConfigurationVersionUtils
  • New events added to UaPubSubApplication
        /// <summary>
        /// Event that is triggered when the <see cref="UaPubSubApplication"/> receives and decodes subscribed DataSet MetaData
        /// </summary>
        public event EventHandler<SubscribedDataEventArgs> MetaDataReceived;
        /// <summary>
        /// Event that is triggered before the configuration is updated with a new MetaData 
        /// The configuration will not be updated if <see cref="ConfigurationUpdatingEventArgs.Cancel"/> flag is set on true.
        /// </summary>
        public event EventHandler<ConfigurationUpdatingEventArgs> ConfigurationUpdating;
  • Unit tests were updated to cover the new functionality

AlinMoldovean and others added 30 commits July 12, 2021 12:25
Update sample apps to be able to start suing MQTT & UADP
Fix tests because they fail after creating also the dataset metadata messages together with dataset messages
…n publisherId value is provided as positive signed type
…iate between detected Metadata version changes
…n publisherId value is provided as positive signed type
…iate between detected Metadata version changes
@mregen mregen linked an issue Sep 20, 2021 that may be closed by this pull request
1 task
@mregen
Copy link
Contributor

mregen commented Sep 20, 2021

Please check new lgtm alerts and remove launchsettings.json from list of added files

@lgtm-com
Copy link

lgtm-com bot commented Sep 21, 2021

This pull request introduces 22 alerts and fixes 5 when merging 1d1d832 into 7d310d5 - view on LGTM.com

new alerts:

  • 11 for Dereferenced variable may be null
  • 8 for Useless assignment to local variable
  • 1 for Invalid string formatting
  • 1 for Futile conditional
  • 1 for Poor error handling: empty catch block

fixed alerts:

  • 4 for Dereferenced variable may be null
  • 1 for Poor error handling: empty catch block

writerGroup1.DataSetWriters.Add(dataSetWriter1);

// Define DataSetWriter 'AllTypes'
DataSetWriterDataType dataSetWriter2 = new DataSetWriterDataType();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a number of IEncodeable datatypes which are defined in Core as partial class. Imho they are all candidates for simplifying the use by adding partial class helpers in core.

dataSetWriter2.DataSetName = "AllTypes";
dataSetWriter2.KeyFrameCount = 1;
uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
ConfiguredSize = 32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this calculated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree to this complain, since one has to have the specification and has to calculate these values.

dataSetWriter2.KeyFrameCount = 1;
uadpDataSetWriterMessage = new UadpDataSetWriterMessageDataType() {
ConfiguredSize = 32,
DataSetOffset = 47,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I totally agree.

Copy link
Contributor

@mregen mregen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a couple of architectural improvements that need to happen to make this implementation better usable across platforms.. but not necessarily need to happen for this PR

  • specify more interface abstractions where necessary, e.g. IJsonEncoder/IJsonDecoder to be able to decouple from the default implementation.
  • refactor some of the partial PubSub base types to have a complement in core to make them easier to use
  • refactor the core encoding/decoding NetworkMessage/DataSetMessage classes to be based on interface classes, not abstract classes.
  • Seperate implementation from application code by moving some classes in core, e.g. JsonNetworkMessage/UadpNetWorkmessage etc
  • there is a hack to use GlobalContext for namespaceUri
  • is the discoveryResponse part of the 1.04 spec or ist it ported from the starter kit code?

publishedDataSetSimple.DataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() {
MinorVersion = 1,
MajorVersion = 1
MinorVersion = ConfigurationVersionUtils.CalculateVersionTime(kTimeOfConfiguration),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. such a default init could be part of a partial class in core, extending ConfigurationVersionDataType

// constant DateTime that represents the initial time when the metadata for the configuration was created
private static DateTime kTimeOfConfiguration = new DateTime(2021, 5, 1, 0, 0, 0, DateTimeKind.Utc);
private const string kDisplaySeparator = "------------------------------------------------";

private static object m_lock = new object();

public static void Main(string[] args)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general note to the sample code to improve for FUTURE: The construction of the PubSub configuration looks complicated and error prone, it would be nice to have 'fluent API' or helper extension functions to build the structure content. Its unclear to me how some of the offset are calculated, so if this could be done by such an API would make the job a lot easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally agree with your above observations and we are thinking of implementing such a "fluent API".

@@ -179,10 +178,7 @@ public void SetNetworkMessageContentMask(JsonNetworkMessageContentMask networkMe
/// <returns></returns>
public override byte[] Encode()
{
IServiceMessageContext messageContext = new ServiceMessageContext {
NamespaceUris = ServiceMessageContext.GlobalContext.NamespaceUris,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to directly use the GlobalContext here seems like a hack

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, we will have to refactor this method and pass the messageContext as a parameter.
We recall that you requested that an Encode method should exist without any parameters, is it ok in your opinion that we refactor it and add the IServiceMessageContext parameter?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, that would make sense.

@mregen
Copy link
Contributor

mregen commented Sep 21, 2021

half way through -- will continue review later

@lgtm-com
Copy link

lgtm-com bot commented Sep 21, 2021

This pull request introduces 8 alerts and fixes 6 when merging 510c34c into 7d310d5 - view on LGTM.com

new alerts:

  • 6 for Dereferenced variable may be null
  • 2 for Useless assignment to local variable

fixed alerts:

  • 5 for Dereferenced variable may be null
  • 1 for Poor error handling: empty catch block

Copy link
Contributor

@mregen mregen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mrsuciu , looks good for this release since we are still in preview state. For the long run some architectural changes should be considered, mainly around refactories some dtaatypes and classes. Please see my previous comment.

@@ -206,9 +247,10 @@ private static void UaPubSubApplication_MetaDataDataReceived(object sender, Subs
{
lock (m_lock)
{
Console.WriteLine("MetaDataDataReceived event:");
if (e.NetworkMessage is JsonNetworkMessage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to handle the UADP MetaData Message as well, like in the UaPubSubApplication_DataReceived()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cristipogacean Yes, treating the UADP Metadata Message similar to the handling in UaPubSubApplication_DataReceived() is a good idea.

DecodeSubscribedDataSets(decoder, dataSetReaders);
}
}
string json = System.Text.Encoding.ASCII.GetString(message);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the ASCII encoding the right choice here? We might consider using UTF8 since the default encoding for JSON is Unicode.

default:
// Reserved - no type provided
break;
Utils.Trace(TraceMasks.Error, "NetworkMessageHeader cannot be encoded. PublisherId is null but it is expected to be encoded.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should handle this situation with an exception and not generate the inconsistent message at all. Or reset the UADPFlags to reflect the fact that the PublisherId is not part of the encoded message.

@@ -101,7 +101,7 @@ internal class MqttClientCreator

while (mqttClient.IsConnected == false)
{
Connect(reconnectInterval, mqttClientOptions, mqttClient);
await Connect(reconnectInterval, mqttClientOptions, mqttClient);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this lead to an infinite loop in case of a bad configuration of mqtt client?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cristipogacean Yes it can, but the problem here is that the the mqttClient.ConnectAsync called in the Connect method does not set the correct/expected MqttClientConnectResultCode code in case a configuration error is present thus distinguishing between it and a non configuration error such as the server( MQTT broker) not being available becomes impossible. For ex: trying to connect to a broker using an unsupported MQTT protocol version simply throws an exception and does not return as one would expect MqttClientConnectResultCode.ProtocolError. The desired effect of this loop is to allow a connection to connect if the settings are correct and the broker becomes available even after the connection is initiated, of course the undesired effect is that it will loop infinitely if the broker is unreachable or the configuration contains an error.

@lgtm-com
Copy link

lgtm-com bot commented Sep 28, 2021

This pull request introduces 9 alerts and fixes 6 when merging 0d301d9 into 33ae8bb - view on LGTM.com

new alerts:

  • 6 for Dereferenced variable may be null
  • 3 for Useless assignment to local variable

fixed alerts:

  • 5 for Dereferenced variable may be null
  • 1 for Poor error handling: empty catch block

@mrsuciu mrsuciu merged commit 75744e2 into OPCFoundation:master Sep 28, 2021
@mrsuciu mrsuciu deleted the pubSubDev-PR branch September 28, 2021 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support MetaData frames in PubSub
7 participants