Skip to content
This repository was archived by the owner on Jul 29, 2021. It is now read-only.

Commit 7cb875f

Browse files
Merge pull request #98 from hansgschossmann/jsonfix
Create syntactically correct Json messages sent to IoTHub, remove credentials from logfiles
2 parents dfe4670 + 54dd4b1 commit 7cb875f

File tree

4 files changed

+38
-40
lines changed

4 files changed

+38
-40
lines changed

src/IotHubMessaging.cs

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public async Task<bool> InitAsync()
137137
}
138138
else
139139
{
140-
Trace($"Attempting to register ourselves with IoT Hub using owner connection string: {_iotHubOwnerConnectionString}");
140+
Trace($"Attempting to register ourselves with IoT Hub using owner connection string.");
141141
RegistryManager manager = RegistryManager.CreateFromConnectionString(_iotHubOwnerConnectionString);
142142

143143
// remove any existing device
@@ -154,13 +154,13 @@ public async Task<bool> InitAsync()
154154
{
155155
string hostname = _iotHubOwnerConnectionString.Substring(0, _iotHubOwnerConnectionString.IndexOf(";"));
156156
deviceConnectionString = hostname + ";DeviceId=" + ApplicationName + ";SharedAccessKey=" + newDevice.Authentication.SymmetricKey.PrimaryKey;
157-
Trace($"Device connection string is: {deviceConnectionString}");
157+
Trace($"Generated device connection string.");
158158
Trace($"Adding it to device cert store.");
159159
await SecureIoTHubToken.WriteAsync(ApplicationName, deviceConnectionString, IotDeviceCertStoreType, IotDeviceCertStorePath);
160160
}
161161
else
162162
{
163-
Trace($"Could not register ourselves with IoT Hub using owner connection string: {_iotHubOwnerConnectionString}");
163+
Trace($"Could not register ourselves with IoT Hub using owner connection string.");
164164
Trace("exiting...");
165165
return false;
166166
}
@@ -171,7 +171,7 @@ public async Task<bool> InitAsync()
171171
deviceConnectionString = await SecureIoTHubToken.ReadAsync(ApplicationName, IotDeviceCertStoreType, IotDeviceCertStorePath);
172172
if (!string.IsNullOrEmpty(deviceConnectionString))
173173
{
174-
Trace($"Create Publisher IoTHub client with device connection string: '{deviceConnectionString}' using '{IotHubProtocol}' for communication.");
174+
Trace($"Create Publisher IoTHub client with device connection string using '{IotHubProtocol}' for communication.");
175175
_iotHubClient = DeviceClient.CreateFromConnectionString(deviceConnectionString, IotHubProtocol);
176176
ExponentialBackoff exponentialRetryPolicy = new ExponentialBackoff(int.MaxValue, TimeSpan.FromMilliseconds(2), TimeSpan.FromMilliseconds(1024), TimeSpan.FromMilliseconds(3));
177177
_iotHubClient.SetRetryPolicy(exponentialRetryPolicy);
@@ -270,16 +270,12 @@ public void Enqueue(string json)
270270
/// </summary>
271271
private async Task MonitoredItemsProcessor(CancellationToken ct)
272272
{
273-
string contentPropertyKey = "content-type";
274-
string contentPropertyValue = "application/opcua+uajson";
275-
string devicenamePropertyKey = "devicename";
276-
string devicenamePropertyValue = ApplicationName;
277-
int userPropertyLength = contentPropertyKey.Length + contentPropertyValue.Length + devicenamePropertyKey.Length + devicenamePropertyValue.Length;
273+
uint jsonSquareBracketLength = 2;
278274
Microsoft.Azure.Devices.Client.Message tempMsg = new Microsoft.Azure.Devices.Client.Message();
279275
// the system properties are MessageId (max 128 byte), Sequence number (ulong), ExpiryTime (DateTime) and more. ideally we get that from the client.
280276
int systemPropertyLength = 128 + sizeof(ulong) + tempMsg.ExpiryTimeUtc.ToString().Length;
281277
// if batching is requested the buffer will have the requested size, otherwise we reserve the max size
282-
uint iotHubMessageBufferSize = (_iotHubMessageSize > 0 ? _iotHubMessageSize : IotHubMessageSizeMax) - (uint)userPropertyLength - (uint)systemPropertyLength;
278+
uint iotHubMessageBufferSize = (_iotHubMessageSize > 0 ? _iotHubMessageSize : IotHubMessageSizeMax) - (uint)systemPropertyLength - (uint)jsonSquareBracketLength;
283279
byte[] iotHubMessageBuffer = new byte[iotHubMessageBufferSize];
284280
MemoryStream iotHubMessage = new MemoryStream(iotHubMessageBuffer);
285281
DateTime nextSendTime = DateTime.UtcNow + TimeSpan.FromSeconds(_defaultSendIntervalSeconds);
@@ -295,6 +291,7 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
295291

296292
iotHubMessage.Position = 0;
297293
iotHubMessage.SetLength(0);
294+
iotHubMessage.Write(Encoding.UTF8.GetBytes("["), 0, 1);
298295
while (true)
299296
{
300297
// sanity check the send interval, compute the timeout and get the next monitored item message
@@ -327,7 +324,7 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
327324
// sanity check that the user has set a large enough IoTHub messages size
328325
if ((_iotHubMessageSize > 0 && jsonMessageSize > _iotHubMessageSize) || (_iotHubMessageSize == 0 && jsonMessageSize > iotHubMessageBufferSize))
329326
{
330-
Trace(Utils.TraceMasks.Error, $"There is a telemetry message (size: {jsonMessageSize}), which will not fit into an IoTHub message (max size: {_iotHubMessageSize}].");
327+
Trace(Utils.TraceMasks.Error, $"There is a telemetry message (size: {jsonMessageSize}), which will not fit into an IoTHub message (max size: {iotHubMessageBufferSize}].");
331328
Trace(Utils.TraceMasks.Error, $"Please check your IoTHub message size settings. The telemetry message will be discarded silently. Sorry:(");
332329
_tooLargeCount++;
333330
continue;
@@ -338,10 +335,12 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
338335
if (_iotHubMessageSize > 0 || (_iotHubMessageSize == 0 && _defaultSendIntervalSeconds > 0))
339336
{
340337
// if there is still space to batch, do it. otherwise send the buffer and flag the message for later buffering
341-
if (iotHubMessage.Position + jsonMessageSize <= iotHubMessage.Capacity)
338+
if (iotHubMessage.Position + jsonMessageSize + 1 <= iotHubMessage.Capacity)
342339
{
340+
// add the message and a comma to the buffer
343341
iotHubMessage.Write(Encoding.UTF8.GetBytes(jsonMessage.ToString()), 0, jsonMessageSize);
344-
Trace(Utils.TraceMasks.OperationDetail, $"Added new message with size {jsonMessageSize} to IoTHub message (size is now {iotHubMessage.Position}).");
342+
iotHubMessage.Write(Encoding.UTF8.GetBytes(","), 0, 1);
343+
Trace(Utils.TraceMasks.OperationDetail, $"Added new message with size {jsonMessageSize} to IoTHub message (size is now {(iotHubMessage.Position - 1)}).");
345344
continue;
346345
}
347346
else
@@ -368,25 +367,28 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
368367
Microsoft.Azure.Devices.Client.Message encodedIotHubMessage = null;
369368

370369
// if we reached the send interval, but have nothing to send, we continue
371-
if (!gotItem && iotHubMessage.Position == 0)
370+
if (!gotItem && iotHubMessage.Position == 1)
372371
{
373372
nextSendTime += TimeSpan.FromSeconds(_defaultSendIntervalSeconds);
374373
iotHubMessage.Position = 0;
375374
iotHubMessage.SetLength(0);
375+
iotHubMessage.Write(Encoding.UTF8.GetBytes("["), 0, 1);
376376
continue;
377377
}
378378

379379
// if there is no batching and not interval configured, we send the JSON message we just got, otherwise we send the buffer
380380
if (_iotHubMessageSize == 0 && _defaultSendIntervalSeconds == 0)
381381
{
382-
encodedIotHubMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes(jsonMessage.ToString()));
382+
// we use also an array for a single message to make backend processing more consistent
383+
encodedIotHubMessage = new Microsoft.Azure.Devices.Client.Message(Encoding.UTF8.GetBytes("[" + jsonMessage.ToString() + "]"));
383384
}
384385
else
385386
{
387+
// remove the trailing comma and add a closing square bracket
388+
iotHubMessage.SetLength(iotHubMessage.Length - 1);
389+
iotHubMessage.Write(Encoding.UTF8.GetBytes("]"), 0, 1);
386390
encodedIotHubMessage = new Microsoft.Azure.Devices.Client.Message(iotHubMessage.ToArray());
387391
}
388-
encodedIotHubMessage.Properties.Add(contentPropertyKey, contentPropertyValue);
389-
encodedIotHubMessage.Properties.Add(devicenamePropertyKey, devicenamePropertyValue);
390392
if (_iotHubClient != null)
391393
{
392394
nextSendTime += TimeSpan.FromSeconds(_defaultSendIntervalSeconds);
@@ -406,11 +408,14 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
406408
// reset the messaage
407409
iotHubMessage.Position = 0;
408410
iotHubMessage.SetLength(0);
411+
iotHubMessage.Write(Encoding.UTF8.GetBytes("["), 0, 1);
409412

410413
// if we had not yet buffered the last message because there was not enough space, buffer it now
411414
if (needToBufferMessage)
412415
{
416+
// add the message and a comma to the buffer
413417
iotHubMessage.Write(Encoding.UTF8.GetBytes(jsonMessage.ToString()), 0, jsonMessageSize);
418+
iotHubMessage.Write(Encoding.UTF8.GetBytes(","), 0, 1);
414419
}
415420
}
416421
else
@@ -459,23 +464,5 @@ private async Task MonitoredItemsProcessor(CancellationToken ct)
459464
private static CancellationTokenSource _tokenSource;
460465
private static Task _monitoredItemsProcessorTask;
461466
private static DeviceClient _iotHubClient;
462-
463-
/// <summary>
464-
/// Classes for the telemetry message sent to IoTHub.
465-
/// </summary>
466-
private class OpcUaMessage
467-
{
468-
public string ApplicationUri;
469-
public string DisplayName;
470-
public string NodeId;
471-
public OpcUaValue Value;
472-
}
473-
474-
private class OpcUaValue
475-
{
476-
public string Value;
477-
public string SourceTimestamp;
478-
}
479-
480467
}
481468
}

src/OpcSession.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public enum OpcMonitoredItemConfigurationType
4747
public MonitoredItem OpcUaClientMonitoredItem;
4848
public NodeId ConfigNodeId;
4949
public ExpandedNodeId ConfigExpandedNodeId;
50+
public ExpandedNodeId ConfigExpandedNodeIdOriginal;
5051
public OpcMonitoredItemConfigurationType ConfigType;
5152

5253
/// <summary>
@@ -56,6 +57,7 @@ public OpcMonitoredItem(NodeId nodeId, Uri sessionEndpointUri, bool requestNames
5657
{
5758
ConfigNodeId = nodeId;
5859
ConfigExpandedNodeId = null;
60+
ConfigExpandedNodeIdOriginal = null;
5961
ConfigType = OpcMonitoredItemConfigurationType.NodeId;
6062
Init(sessionEndpointUri);
6163
if (requestNamespaceUpdate)
@@ -71,6 +73,7 @@ public OpcMonitoredItem(ExpandedNodeId expandedNodeId, Uri sessionEndpointUri, b
7173
{
7274
ConfigNodeId = null;
7375
ConfigExpandedNodeId = expandedNodeId;
76+
ConfigExpandedNodeIdOriginal = expandedNodeId;
7477
ConfigType = OpcMonitoredItemConfigurationType.ExpandedNodeId;
7578
Init(sessionEndpointUri);
7679
if (requestNamespaceUpdate)
@@ -166,7 +169,7 @@ public void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredIte
166169
encoder.WriteString("DisplayName", monitoredItem.DisplayName);
167170

168171
// use the node Id as configured, to also have the namespace URI in case of a ExpandedNodeId.
169-
encoder.WriteString("NodeId", ConfigType == OpcMonitoredItemConfigurationType.NodeId ? ConfigNodeId.ToString() : ConfigExpandedNodeId.ToString());
172+
encoder.WriteString("NodeId", ConfigType == OpcMonitoredItemConfigurationType.NodeId ? ConfigNodeId.ToString() : ConfigExpandedNodeIdOriginal.ToString());
170173

171174
// suppress output of server timestamp in json by setting it to minvalue
172175
value.ServerTimestamp = DateTime.MinValue;

src/OpcStackConfiguration.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,16 @@ public static int OpcKeepAliveIntervalInSec
8686
set => _opcKeepAliveIntervalInSec = value;
8787
}
8888

89+
public const int OpcSamplingIntervalDefault = 1000;
90+
8991
public static int OpcSamplingInterval
9092
{
9193
get => _opcSamplingInterval;
9294
set => _opcSamplingInterval = value;
9395
}
9496

97+
public const int OpcPublishingIntervalDefault = 0;
98+
9599
public static int OpcPublishingInterval
96100
{
97101
get => _opcPublishingInterval;
@@ -408,8 +412,8 @@ public async Task ConfigureAsync()
408412
private static uint _opcSessionCreationBackoffMax = 5;
409413
private static uint _opcKeepAliveDisconnectThreshold = 5;
410414
private static int _opcKeepAliveIntervalInSec = 2;
411-
private static int _opcSamplingInterval = 1000;
412-
private static int _opcPublishingInterval = 0;
415+
private static int _opcSamplingInterval = OpcSamplingIntervalDefault;
416+
private static int _opcPublishingInterval = OpcPublishingIntervalDefault;
413417
private static string _publisherServerSecurityPolicy = SecurityPolicies.Basic128Rsa15;
414418
private static string _opcOwnCertStoreType = X509Store;
415419
private static string _opcOwnCertStorePath = OpcOwnCertX509StorePathDefault;

src/PublisherNodeConfiguration.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace OpcPublisher
99
{
10+
using System.ComponentModel;
1011
using System.IO;
1112
using System.Linq;
1213
using System.Threading;
@@ -384,9 +385,12 @@ public static async Task UpdateNodeConfigurationFile()
384385
public class OpcNodeOnEndpointUrl
385386
{
386387
public string ExpandedNodeId;
387-
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
388+
[DefaultValue(OpcSamplingIntervalDefault)]
389+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore)]
388390
public int? OpcSamplingInterval;
389-
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
391+
392+
[DefaultValue(OpcPublishingIntervalDefault)]
393+
[JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore)]
390394
public int? OpcPublishingInterval;
391395
}
392396

0 commit comments

Comments
 (0)