History

TimeSeriesPlatformLibrary: Added temporal support options to DataPublisher interfaces.

J. Ritchie Carroll committed 7 years ago

Commit 5c5b4061 parent 04505f228 files · +603 −300Browse files

Showing the changes to Source/Libraries (26 of 28 files). Show all

Unified · Split

26 files
  1. Source/Libraries/TimeSeriesPlatformLibrary/Common/CommonTypes.cpp +12 −8
  2. Source/Libraries/TimeSeriesPlatformLibrary/Common/CommonTypes.h +21 −9
  3. Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.cpp +49 −17
  4. Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.h +12 −8
  5. Source/Libraries/TimeSeriesPlatformLibrary/Common/Nullable.h +1 −1
  6. Source/Libraries/TimeSeriesPlatformLibrary/Data/DataRow.cpp +7 −7
  7. Source/Libraries/TimeSeriesPlatformLibrary/Data/DataRow.h +4 −4
  8. Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/ExpressionTree.cpp +9 −9
  9. Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/ExpressionTree.h +2 −2
  10. Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/FilterExpressionParser.cpp +1 −1
  11. Source/Libraries/TimeSeriesPlatformLibrary/Samples/AdvancedPublish.cpp +35 −11
  12. Source/Libraries/TimeSeriesPlatformLibrary/Samples/FilterExpressionTests.cpp +9 −9
  13. Source/Libraries/TimeSeriesPlatformLibrary/Samples/SimplePublish.cpp +9 −9
  14. Source/Libraries/TimeSeriesPlatformLibrary/Samples/SubscriberHandler.cpp +1 −1
  15. Source/Libraries/TimeSeriesPlatformLibrary/Samples/SubscriberHandler.h +1 −1
  16. Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataPublisher.cpp +94 −34
  17. Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataPublisher.h +34 −13
  18. Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataSubscriber.h +10 −9
  19. Source/Libraries/TimeSeriesPlatformLibrary/Transport/PublisherInstance.cpp +32 −8
  20. Source/Libraries/TimeSeriesPlatformLibrary/Transport/PublisherInstance.h +8 −4
  21. Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberConnection.cpp +114 −58
  22. Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberConnection.h +48 −5
  23. Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberInstance.cpp +4 −4
  24. Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberInstance.h +1 −1
  25. Source/Libraries/TimeSeriesPlatformLibrary/Transport/TransportTypes.cpp +18 −1
  26. Source/Libraries/TimeSeriesPlatformLibrary/Transport/TransportTypes.h +5 −4
Source/Libraries/TimeSeriesPlatformLibrary/Common/CommonTypes.cpp+12−8
@@ -45,9 +45,13 @@ const decimal_t Decimal::DotNetMaxValue = decimal_t("792281625142643375935439503 · 44 unmodified lines
45 45
46const decimal_t Decimal::DotNetMinValue = decimal_t("-79228162514264337593543950335");46const decimal_t Decimal::DotNetMinValue = decimal_t("-79228162514264337593543950335");
47 47
48const datetime_t DateTime::MaxValue(max_date_time);
49
50const datetime_t DateTime::MinValue(min_date_time);
51
48const string Empty::String {};52const string Empty::String {};
49 53
50const DateTime Empty::DateTime {};54const datetime_t Empty::DateTime {};
51 55
52const Guid Empty::Guid = NilGuidGen();56const Guid Empty::Guid = NilGuidGen();
53 57
@@ -280,7 +284,7 @@ string GSF::PadRight(const string& value, uint32_t count, char padChar) · 226 unmodified lines
280 return value;284 return value;
281}285}
282 286
283DateTime GSF::DateAdd(const DateTime& value, int32_t addValue, TimeInterval interval)287datetime_t GSF::DateAdd(const datetime_t& value, int32_t addValue, TimeInterval interval)
284{288{
285 switch (interval)289 switch (interval)
286 {290 {
@@ -307,7 +311,7 @@ DateTime GSF::DateAdd(const DateTime& value, int32_t addValue, TimeInterval inte · 20 unmodified lines
307 }311 }
308}312}
309 313
310int32_t GSF::DateDiff(const DateTime& startTime, const DateTime& endTime, TimeInterval interval)314int32_t GSF::DateDiff(const datetime_t& startTime, const datetime_t& endTime, TimeInterval interval)
311{315{
312 if (interval < TimeInterval::Hour)316 if (interval < TimeInterval::Hour)
313 {317 {
@@ -345,7 +349,7 @@ int32_t GSF::DateDiff(const DateTime& startTime, const DateTime& endTime, TimeIn · 31 unmodified lines
345 }349 }
346}350}
347 351
348int32_t GSF::DatePart(const DateTime& value, TimeInterval interval)352int32_t GSF::DatePart(const datetime_t& value, TimeInterval interval)
349{353{
350 static float64_t tickInterval = pow(10.0, time_duration::num_fractional_digits());354 static float64_t tickInterval = pow(10.0, time_duration::num_fractional_digits());
351 355
@@ -376,12 +380,12 @@ int32_t GSF::DatePart(const DateTime& value, TimeInterval interval) · 24 unmodified lines
376 }380 }
377}381}
378 382
379DateTime GSF::Now()383datetime_t GSF::Now()
380{384{
381 return DateTime { microsec_clock::local_time() };385 return datetime_t { microsec_clock::local_time() };
382}386}
383 387
384DateTime GSF::UtcNow()388datetime_t GSF::UtcNow()
385{389{
386 return DateTime { microsec_clock::universal_time() };390 return datetime_t { microsec_clock::universal_time() };
387}391}
Source/Libraries/TimeSeriesPlatformLibrary/Common/CommonTypes.h+21−9
@@ -48,6 +48,9 @@ namespace GSF · 47 unmodified lines
48 typedef double_t float64_t;48 typedef double_t float64_t;
49 typedef boost::multiprecision::cpp_dec_float_100 decimal_t;49 typedef boost::multiprecision::cpp_dec_float_100 decimal_t;
50 50
51 // DateTime type
52 typedef boost::posix_time::ptime datetime_t;
53
51 struct Int854 struct Int8
52 {55 {
53 static const int8_t MaxValue = static_cast<int8_t>(127);56 static const int8_t MaxValue = static_cast<int8_t>(127);
@@ -105,16 +108,26 @@ namespace GSF · 51 unmodified lines
105 static const decimal_t DotNetMinValue;108 static const decimal_t DotNetMinValue;
106 };109 };
107 110
111 struct DateTime
112 {
113 static const datetime_t MaxValue;
114 static const datetime_t MinValue;
115 };
116
108 struct Ticks117 struct Ticks
109 {118 {
119 static const int64_t MaxValue = 3155378975999999999L; // 12/31/1999 11:59:59.999
120 static const int64_t MinValue = 0L; // 01/01/0001 00:00:00.000
121
122 static const int64_t UnixBaseOffset = 621355968000000000L; // 01/01/1970 00:00:00.000
123 static const int64_t PTimeBaseOffset = 441481536000000000L; // 01/01/1400 00:00:00.000
124
110 static const int64_t PerSecond = 10000000L;125 static const int64_t PerSecond = 10000000L;
111 static const int64_t PerMillisecond = Ticks::PerSecond / 1000;126 static const int64_t PerMillisecond = Ticks::PerSecond / 1000;
112 static const int64_t PerMicrosecond = Ticks::PerSecond / 1000000;127 static const int64_t PerMicrosecond = Ticks::PerSecond / 1000000;
113 static const int64_t PerMinute = 60L * Ticks::PerSecond;128 static const int64_t PerMinute = 60L * Ticks::PerSecond;
114 static const int64_t PerHour = 60L * Ticks::PerMinute;129 static const int64_t PerHour = 60L * Ticks::PerMinute;
115 static const int64_t PerDay = 24L * Ticks::PerHour;130 static const int64_t PerDay = 24L * Ticks::PerHour;
116 static const int64_t UnixBaseOffset = 621355968000000000L; // 01/01/1970 00:00:00
117 static const int64_t PtimeBaseOffset = 441481536000000000L; // 01/01/1400 00:00:00
118 };131 };
119 132
120 template<class T>133 template<class T>
@@ -167,7 +180,6 @@ namespace GSF · 46 unmodified lines
167 180
168 typedef boost::any Object;181 typedef boost::any Object;
169 typedef boost::uuids::uuid Guid;182 typedef boost::uuids::uuid Guid;
170 typedef boost::posix_time::ptime DateTime;
171 typedef boost::posix_time::time_duration TimeSpan;183 typedef boost::posix_time::time_duration TimeSpan;
172 typedef boost::system::error_code ErrorCode;184 typedef boost::system::error_code ErrorCode;
173 typedef boost::system::system_error SystemError;185 typedef boost::system::system_error SystemError;
@@ -192,7 +204,7 @@ namespace GSF · 18 unmodified lines
192 struct Empty204 struct Empty
193 {205 {
194 static const std::string String;206 static const std::string String;
195 static const GSF::DateTime DateTime;207 static const GSF::datetime_t DateTime;
196 static const GSF::Guid Guid;208 static const GSF::Guid Guid;
197 static const GSF::Object Object;209 static const GSF::Object Object;
198 static const GSF::IPAddress IPAddress;210 static const GSF::IPAddress IPAddress;
@@ -394,11 +406,11 @@ namespace GSF · 195 unmodified lines
394 Millisecond406 Millisecond
395 };407 };
396 408
397 DateTime DateAdd(const DateTime& value, int32_t addValue, TimeInterval interval);409 datetime_t DateAdd(const datetime_t& value, int32_t addValue, TimeInterval interval);
398 int32_t DateDiff(const DateTime& startTime, const DateTime& endTime, TimeInterval interval);410 int32_t DateDiff(const datetime_t& startTime, const datetime_t& endTime, TimeInterval interval);
399 int32_t DatePart(const DateTime& value, TimeInterval interval);411 int32_t DatePart(const datetime_t& value, TimeInterval interval);
400 DateTime Now();412 datetime_t Now();
401 DateTime UtcNow();413 datetime_t UtcNow();
402}414}
403 415
404// Setup standard hash code for Guid416// Setup standard hash code for Guid
Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.cpp+49−17
@@ -40,7 +40,7 @@ using namespace boost::posix_time; · 39 unmodified lines
40using namespace boost::gregorian;40using namespace boost::gregorian;
41using namespace GSF;41using namespace GSF;
42 42
43const DateTime DateTimeEpoch(date(1400, 1, 1), time_duration(0, 0, 0));43const datetime_t DateTimeEpoch(date(1400, 1, 1), time_duration(0, 0, 0));
44const auto DateTimeTicksPerSecond = time_duration::ticks_per_second();44const auto DateTimeTicksPerSecond = time_duration::ticks_per_second();
45 45
46string PreparseTimestamp(const string& timestamp, time_duration& utcOffset)46string PreparseTimestamp(const string& timestamp, time_duration& utcOffset)
@@ -161,24 +161,24 @@ void GSF::ToUnixTime(const int64_t ticks, time_t& unixSOC, uint16_t& millisecond · 114 unmodified lines
161 milliseconds = static_cast<uint16_t>(ticks / 10000 % 1000);161 milliseconds = static_cast<uint16_t>(ticks / 10000 % 1000);
162}162}
163 163
164DateTime GSF::FromUnixTime(time_t unixSOC, uint16_t milliseconds)164datetime_t GSF::FromUnixTime(time_t unixSOC, uint16_t milliseconds)
165{165{
166 return from_time_t(unixSOC) + boost::posix_time::milliseconds(milliseconds);166 return from_time_t(unixSOC) + boost::posix_time::milliseconds(milliseconds);
167}167}
168 168
169DateTime GSF::FromTicks(const int64_t ticks)169datetime_t GSF::FromTicks(const int64_t ticks)
170{170{
171 static float64_t tickInterval = float64_t(Ticks::PerSecond);171 static float64_t tickInterval = float64_t(Ticks::PerSecond);
172 const DateTime time = from_time_t((ticks - Ticks::UnixBaseOffset) / Ticks::PerSecond);172 const datetime_t time = from_time_t((ticks - Ticks::UnixBaseOffset) / Ticks::PerSecond);
173 const int64_t pticks = int64_t(ticks % Ticks::PerSecond / tickInterval * DateTimeTicksPerSecond);173 const int64_t pticks = int64_t(ticks % Ticks::PerSecond / tickInterval * DateTimeTicksPerSecond);
174 return time + time_duration(0, 0, 0, pticks % DateTimeTicksPerSecond);174 return time + time_duration(0, 0, 0, pticks % DateTimeTicksPerSecond);
175}175}
176 176
177int64_t GSF::ToTicks(const DateTime& time)177int64_t GSF::ToTicks(const datetime_t& time)
178{178{
179 static float64_t tickInterval = pow(10.0, time_duration::num_fractional_digits());179 static float64_t tickInterval = pow(10.0, time_duration::num_fractional_digits());
180 const time_duration offset = time - DateTimeEpoch;180 const time_duration offset = time - DateTimeEpoch;
181 return Ticks::PtimeBaseOffset + offset.total_seconds() * Ticks::PerSecond +181 return Ticks::PTimeBaseOffset + offset.total_seconds() * Ticks::PerSecond +
182 int64_t(offset.fractional_seconds() / tickInterval * Ticks::PerSecond);182 int64_t(offset.fractional_seconds() / tickInterval * Ticks::PerSecond);
183}183}
184 184
@@ -240,9 +240,9 @@ uint32_t GSF::TicksToString(char* ptr, uint32_t maxsize, string format, int64_t · 55 unmodified lines
240 return strftime(ptr, maxsize, formatStream.str().data(), &timeinfo);240 return strftime(ptr, maxsize, formatStream.str().data(), &timeinfo);
241}241}
242 242
243DateTime GSF::LocalFromUtc(const DateTime& timestamp)243datetime_t GSF::LocalFromUtc(const datetime_t& timestamp)
244{244{
245 return boost::date_time::c_local_adjustor<DateTime>::utc_to_local(timestamp);245 return boost::date_time::c_local_adjustor<datetime_t>::utc_to_local(timestamp);
246}246}
247 247
248std::string GSF::ToString(const Guid& value)248std::string GSF::ToString(const Guid& value)
@@ -250,7 +250,7 @@ std::string GSF::ToString(const Guid& value) · 1 unmodified line
250 return boost::uuids::to_string(value);250 return boost::uuids::to_string(value);
251}251}
252 252
253std::string GSF::ToString(const DateTime& value, const char* format)253std::string GSF::ToString(const datetime_t& value, const char* format)
254{254{
255 stringstream stream;255 stringstream stream;
256 time_facet* facet = new time_facet(format);256 time_facet* facet = new time_facet(format);
@@ -309,7 +309,35 @@ bool GSF::ParseBoolean(const string& value) · 52 unmodified lines
309 return false;309 return false;
310}310}
311 311
312bool GSF::TryParseDouble(const string& value, float64_t& result)312bool GSF::TryParseInt32(const std::string& value, int32_t& result, const int32_t defaultValue)
313{
314 try
315 {
316 result = stoi(value);
317 return true;
318 }
319 catch (...)
320 {
321 result = defaultValue;
322 return false;
323 }
324}
325
326bool GSF::TryParseInt64(const std::string& value, int64_t& result, const int64_t defaultValue)
327{
328 try
329 {
330 result = stoll(value);
331 return true;
332 }
333 catch (...)
334 {
335 result = defaultValue;
336 return false;
337 }
338}
339
340bool GSF::TryParseDouble(const string& value, float64_t& result, const float64_t defaultValue)
313{341{
314 try342 try
315 {343 {
@@ -318,6 +346,7 @@ bool GSF::TryParseDouble(const string& value, float64_t& result) · 2 unmodified lines
318 }346 }
319 catch (...)347 catch (...)
320 {348 {
349 result = defaultValue;
321 return false;350 return false;
322 }351 }
323}352}
@@ -428,8 +457,8 @@ const char* GSF::Coalesce(const char* data, const char* nonEmptyValue) · 104 unmodified lines
428 return data;457 return data;
429}458}
430 459
431// Parse a timestamp string, e.g.: 2018-03-14T19:23:11.665-04:00460// Attempt to parse a timestamp string, e.g.: 2018-03-14T19:23:11.665-04:00
432bool GSF::TryParseTimestamp(const char* time, DateTime& timestamp, bool parseAsUTC)461bool GSF::TryParseTimestamp(const char* time, datetime_t& timestamp, const datetime_t& defaultValue, bool parseAsUTC)
433{462{
434 static const locale formats[] = {463 static const locale formats[] = {
435 locale(locale::classic(), new time_input_facet("%Y-%m-%d %H:%M:%S%F")),464 locale(locale::classic(), new time_input_facet("%Y-%m-%d %H:%M:%S%F")),
@@ -438,10 +467,12 @@ bool GSF::TryParseTimestamp(const char* time, DateTime& timestamp, bool parseAsU · 2 unmodified lines
438 467
439 static const int32_t formatsCount = sizeof(formats) / sizeof(formats[0]);468 static const int32_t formatsCount = sizeof(formats) / sizeof(formats[0]);
440 469
470 time_duration utcOffset{};
471 const string cleanTimestamp = PreparseTimestamp(time, utcOffset);
472
441 for (int32_t i = 0; i < formatsCount; i++)473 for (int32_t i = 0; i < formatsCount; i++)
442 {474 {
443 time_duration utcOffset{};475 istringstream stream(cleanTimestamp);
444 istringstream stream(PreparseTimestamp(time, utcOffset));
445 476
446 stream.imbue(formats[i]);477 stream.imbue(formats[i]);
447 stream >> timestamp;478 stream >> timestamp;
@@ -455,14 +486,15 @@ bool GSF::TryParseTimestamp(const char* time, DateTime& timestamp, bool parseAsU · 7 unmodified lines
455 }486 }
456 }487 }
457 488
489 timestamp = defaultValue;
458 return false;490 return false;
459}491}
460 492
461DateTime GSF::ParseTimestamp(const char* time, bool parseAsUTC)493datetime_t GSF::ParseTimestamp(const char* time, bool parseAsUTC)
462{494{
463 DateTime timestamp;495 datetime_t timestamp;
464 496
465 if (TryParseTimestamp(time, timestamp, parseAsUTC))497 if (TryParseTimestamp(time, timestamp, DateTime::MinValue, parseAsUTC))
466 return timestamp;498 return timestamp;
467 499
468 throw runtime_error("Failed to parse timestamp \"" + string(time) + "\"");500 throw runtime_error("Failed to parse timestamp \"" + string(time) + "\"");
Source/Libraries/TimeSeriesPlatformLibrary/Common/Convert.h+12−8
@@ -32,18 +32,18 @@ namespace GSF · 31 unmodified lines
32 void ToUnixTime(int64_t ticks, time_t& unixSOC, uint16_t& milliseconds);32 void ToUnixTime(int64_t ticks, time_t& unixSOC, uint16_t& milliseconds);
33 33
34 // Convert Unix second of century and milliseconds to DateTime34 // Convert Unix second of century and milliseconds to DateTime
35 DateTime FromUnixTime(time_t unixSOC, uint16_t milliseconds);35 datetime_t FromUnixTime(time_t unixSOC, uint16_t milliseconds);
36 36
37 // Converts a timestamp, in Ticks, to DateTime37 // Converts a timestamp, in Ticks, to DateTime
38 DateTime FromTicks(int64_t ticks);38 datetime_t FromTicks(int64_t ticks);
39 39
40 // Converts a DateTime to Ticks40 // Converts a DateTime to Ticks
41 int64_t ToTicks(const DateTime& time);41 int64_t ToTicks(const datetime_t& time);
42 42
43 // Thin wrapper around strftime to provide formats for milliseconds (%f) and full-resolution ticks (%t)43 // Thin wrapper around strftime to provide formats for milliseconds (%f) and full-resolution ticks (%t)
44 uint32_t TicksToString(char* ptr, uint32_t maxsize, std::string format, int64_t ticks);44 uint32_t TicksToString(char* ptr, uint32_t maxsize, std::string format, int64_t ticks);
45 45
46 DateTime LocalFromUtc(const DateTime& timestamp);46 datetime_t LocalFromUtc(const datetime_t& timestamp);
47 47
48 // Converts an object to a string48 // Converts an object to a string
49 template<class T>49 template<class T>
@@ -56,7 +56,7 @@ namespace GSF · 6 unmodified lines
56 56
57 std::string ToString(const Guid& value);57 std::string ToString(const Guid& value);
58 58
59 std::string ToString(const DateTime& value, const char* format = "%Y-%m-%d %H:%M:%S%F");59 std::string ToString(const datetime_t& value, const char* format = "%Y-%m-%d %H:%M:%S%F");
60 60
61 std::string ToString(const TimeSpan& value);61 std::string ToString(const TimeSpan& value);
62 62
@@ -74,7 +74,11 @@ namespace GSF · 11 unmodified lines
74 74
75 bool ParseBoolean(const std::string& value);75 bool ParseBoolean(const std::string& value);
76 76
77 bool TryParseDouble(const std::string& value, float64_t& result);77 bool TryParseInt32(const std::string& value, int32_t& result, int32_t defaultValue = 0);
78
79 bool TryParseInt64(const std::string& value, int64_t& result, int64_t defaultValue = 0L);
80
81 bool TryParseDouble(const std::string& value, float64_t& result, float64_t defaultValue = 0.0);
78 82
79 // Encodes a character value into an escaped RegEx value83 // Encodes a character value into an escaped RegEx value
80 std::string RegExEncode(char value);84 std::string RegExEncode(char value);
@@ -88,10 +92,10 @@ namespace GSF · 7 unmodified lines
88 const char* Coalesce(const char* data, const char* nonEmptyValue);92 const char* Coalesce(const char* data, const char* nonEmptyValue);
89 93
90 // Attempts to parse an time string in several common formats94 // Attempts to parse an time string in several common formats
91 bool TryParseTimestamp(const char* time, DateTime& timestamp, bool parseAsUTC = true);95 bool TryParseTimestamp(const char* time, datetime_t& timestamp, const datetime_t& defaultValue = DateTime::MinValue, bool parseAsUTC = true);
92 96
93 // Converts a string to a date-time that may be in several common formats97 // Converts a string to a date-time that may be in several common formats
94 DateTime ParseTimestamp(const char* time, bool parseAsUTC = true);98 datetime_t ParseTimestamp(const char* time, bool parseAsUTC = true);
95 99
96 // Parses a string of key/value pairs into a case-insensitive string dictionary100 // Parses a string of key/value pairs into a case-insensitive string dictionary
97 StringMap<std::string> ParseKeyValuePairs(const std::string& value, char parameterDelimiter = ';', char keyValueDelimiter = '=', char startValueDelimiter = '{', char endValueDelimiter = '}');101 StringMap<std::string> ParseKeyValuePairs(const std::string& value, char parameterDelimiter = ';', char keyValueDelimiter = '=', char startValueDelimiter = '{', char endValueDelimiter = '}');
Source/Libraries/TimeSeriesPlatformLibrary/Common/Nullable.h+1−1
@@ -324,7 +324,7 @@ namespace GSF · 323 unmodified lines
324 return {};324 return {};
325 }325 }
326 326
327 inline std::string ToString(const Nullable<DateTime>& value, const char* fmt = "%Y-%m-%d %H:%M:%S%F")327 inline std::string ToString(const Nullable<datetime_t>& value, const char* fmt = "%Y-%m-%d %H:%M:%S%F")
328 {328 {
329 if (value.HasValue())329 if (value.HasValue())
330 return ToString(value.GetValueOrDefault(), fmt);330 return ToString(value.GetValueOrDefault(), fmt);
Source/Libraries/TimeSeriesPlatformLibrary/Data/DataRow.cpp+7−7
@@ -394,7 +394,7 @@ Object DataRow::GetComputedValue(const DataColumnPtr& column, DataType targetTyp · 393 unmodified lines
394 }394 }
395 case ExpressionValueType::DateTime:395 case ExpressionValueType::DateTime:
396 {396 {
397 const DateTime result = sourceValue->ValueAsDateTime();397 const datetime_t result = sourceValue->ValueAsDateTime();
398 const time_t value = to_time_t(result);398 const time_t value = to_time_t(result);
399 399
400 switch (targetType)400 switch (targetType)
@@ -690,22 +690,22 @@ void DataRow::SetBooleanValue(const string& columnName, const Nullable<bool>& va · 289 unmodified lines
690 SetBooleanValue(GetColumnIndex(columnName), value);690 SetBooleanValue(GetColumnIndex(columnName), value);
691}691}
692 692
693Nullable<DateTime> DataRow::ValueAsDateTime(const int32_t columnIndex)693Nullable<datetime_t> DataRow::ValueAsDateTime(const int32_t columnIndex)
694{694{
695 return GetValue<DateTime>(columnIndex, DataType::DateTime);695 return GetValue<datetime_t>(columnIndex, DataType::DateTime);
696}696}
697 697
698Nullable<DateTime> DataRow::ValueAsDateTime(const string& columnName)698Nullable<datetime_t> DataRow::ValueAsDateTime(const string& columnName)
699{699{
700 return ValueAsDateTime(GetColumnIndex(columnName));700 return ValueAsDateTime(GetColumnIndex(columnName));
701}701}
702 702
703void DataRow::SetDateTimeValue(const int32_t columnIndex, const Nullable<DateTime>& value)703void DataRow::SetDateTimeValue(const int32_t columnIndex, const Nullable<datetime_t>& value)
704{704{
705 SetValue<DateTime>(columnIndex, value, DataType::DateTime);705 SetValue<datetime_t>(columnIndex, value, DataType::DateTime);
706}706}
707 707
708void DataRow::SetDateTimeValue(const string& columnName, const Nullable<DateTime>& value)708void DataRow::SetDateTimeValue(const string& columnName, const Nullable<datetime_t>& value)
709{709{
710 SetDateTimeValue(GetColumnIndex(columnName), value);710 SetDateTimeValue(GetColumnIndex(columnName), value);
711}711}
Source/Libraries/TimeSeriesPlatformLibrary/Data/DataRow.h+4−4
@@ -87,10 +87,10 @@ namespace Data · 86 unmodified lines
87 void SetBooleanValue(int32_t columnIndex, const GSF::Nullable<bool>& value);87 void SetBooleanValue(int32_t columnIndex, const GSF::Nullable<bool>& value);
88 void SetBooleanValue(const std::string& columnName, const GSF::Nullable<bool>& value);88 void SetBooleanValue(const std::string& columnName, const GSF::Nullable<bool>& value);
89 89
90 GSF::Nullable<GSF::DateTime> ValueAsDateTime(int32_t columnIndex);90 GSF::Nullable<GSF::datetime_t> ValueAsDateTime(int32_t columnIndex);
91 GSF::Nullable<GSF::DateTime> ValueAsDateTime(const std::string& columnName);91 GSF::Nullable<GSF::datetime_t> ValueAsDateTime(const std::string& columnName);
92 void SetDateTimeValue(int32_t columnIndex, const GSF::Nullable<GSF::DateTime>& value);92 void SetDateTimeValue(int32_t columnIndex, const GSF::Nullable<GSF::datetime_t>& value);
93 void SetDateTimeValue(const std::string& columnName, const GSF::Nullable<GSF::DateTime>& value);93 void SetDateTimeValue(const std::string& columnName, const GSF::Nullable<GSF::datetime_t>& value);
94 94
95 GSF::Nullable<GSF::float32_t> ValueAsSingle(int32_t columnIndex);95 GSF::Nullable<GSF::float32_t> ValueAsSingle(int32_t columnIndex);
96 GSF::Nullable<GSF::float32_t> ValueAsSingle(const std::string& columnName);96 GSF::Nullable<GSF::float32_t> ValueAsSingle(const std::string& columnName);
Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/ExpressionTree.cpp+9−9
@@ -387,24 +387,24 @@ Nullable<Guid> ValueExpression::ValueAsNullableGuid() const · 386 unmodified lines
387 return Cast<Guid>(Value);387 return Cast<Guid>(Value);
388}388}
389 389
390DateTime ValueExpression::ValueAsDateTime() const390datetime_t ValueExpression::ValueAsDateTime() const
391{391{
392 ValidateValueType(ExpressionValueType::DateTime);392 ValidateValueType(ExpressionValueType::DateTime);
393 393
394 if (ValueIsNullable)394 if (ValueIsNullable)
395 return Cast<Nullable<DateTime>>(Value).GetValueOrDefault();395 return Cast<Nullable<datetime_t>>(Value).GetValueOrDefault();
396 396
397 return Cast<DateTime>(Value);397 return Cast<datetime_t>(Value);
398}398}
399 399
400Nullable<DateTime> ValueExpression::ValueAsNullableDateTime() const400Nullable<datetime_t> ValueExpression::ValueAsNullableDateTime() const
401{401{
402 ValidateValueType(ExpressionValueType::DateTime);402 ValidateValueType(ExpressionValueType::DateTime);
403 403
404 if (ValueIsNullable)404 if (ValueIsNullable)
405 return Cast<Nullable<DateTime>>(Value);405 return Cast<Nullable<datetime_t>>(Value);
406 406
407 return Cast<DateTime>(Value);407 return Cast<datetime_t>(Value);
408}408}
409 409
410UnaryExpression::UnaryExpression(const ExpressionUnaryType unaryType, ExpressionPtr value) :410UnaryExpression::UnaryExpression(const ExpressionUnaryType unaryType, ExpressionPtr value) :
@@ -1626,7 +1626,7 @@ ValueExpressionPtr ExpressionTree::IsDate(const ValueExpressionPtr& testValue) c · 1215 unmodified lines
1626 if (testValue->ValueType == ExpressionValueType::DateTime)1626 if (testValue->ValueType == ExpressionValueType::DateTime)
1627 return ExpressionTree::True;1627 return ExpressionTree::True;
1628 1628
1629 DateTime timestamp;1629 datetime_t timestamp;
1630 1630
1631 if (testValue->ValueType == ExpressionValueType::String && TryParseTimestamp(testValue->ValueAsString().c_str(), timestamp))1631 if (testValue->ValueType == ExpressionValueType::String && TryParseTimestamp(testValue->ValueAsString().c_str(), timestamp))
1632 return ExpressionTree::True;1632 return ExpressionTree::True;
@@ -3119,7 +3119,7 @@ ValueExpressionPtr ExpressionTree::Convert(const ValueExpressionPtr& sourceValue · 1486 unmodified lines
3119 }3119 }
3120 case ExpressionValueType::DateTime:3120 case ExpressionValueType::DateTime:
3121 {3121 {
3122 const DateTime result = sourceValue->ValueAsDateTime();3122 const datetime_t result = sourceValue->ValueAsDateTime();
3123 const time_t value = to_time_t(result);3123 const time_t value = to_time_t(result);
3124 3124
3125 switch (targetValueType)3125 switch (targetValueType)
@@ -3236,7 +3236,7 @@ ValueExpressionPtr ExpressionTree::NullValue(const ExpressionValueType targetVal · 110 unmodified lines
3236 case ExpressionValueType::Guid:3236 case ExpressionValueType::Guid:
3237 return NewSharedPtr<ValueExpression>(ExpressionValueType::Guid, Nullable<Guid>(nullptr), true);3237 return NewSharedPtr<ValueExpression>(ExpressionValueType::Guid, Nullable<Guid>(nullptr), true);
3238 case ExpressionValueType::DateTime:3238 case ExpressionValueType::DateTime:
3239 return NewSharedPtr<ValueExpression>(ExpressionValueType::DateTime, Nullable<DateTime>(nullptr), true);3239 return NewSharedPtr<ValueExpression>(ExpressionValueType::DateTime, Nullable<datetime_t>(nullptr), true);
3240 default:3240 default:
3241 return NewSharedPtr<ValueExpression>(ExpressionValueType::Undefined, nullptr);3241 return NewSharedPtr<ValueExpression>(ExpressionValueType::Undefined, nullptr);
3242 }3242 }
Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/ExpressionTree.h+2−2
@@ -127,8 +127,8 @@ namespace FilterExpressions · 126 unmodified lines
127 GSF::Guid ValueAsGuid() const;127 GSF::Guid ValueAsGuid() const;
128 Nullable<GSF::Guid> ValueAsNullableGuid() const;128 Nullable<GSF::Guid> ValueAsNullableGuid() const;
129 129
130 GSF::DateTime ValueAsDateTime() const;130 GSF::datetime_t ValueAsDateTime() const;
131 Nullable<GSF::DateTime> ValueAsNullableDateTime() const;131 Nullable<GSF::datetime_t> ValueAsNullableDateTime() const;
132 };132 };
133 133
134 typedef GSF::SharedPtr<ValueExpression> ValueExpressionPtr;134 typedef GSF::SharedPtr<ValueExpression> ValueExpressionPtr;
Source/Libraries/TimeSeriesPlatformLibrary/FilterExpressions/FilterExpressionParser.cpp+1−1
@@ -59,7 +59,7 @@ static GSF::Guid ParseGuidLiteral(string guidLiteral) · 58 unmodified lines
59 return ParseGuid(guidLiteral.c_str());59 return ParseGuid(guidLiteral.c_str());
60}60}
61 61
62static DateTime ParseDateTimeLiteral(string time)62static datetime_t ParseDateTimeLiteral(string time)
63{63{
64 // Remove any surrounding '#' symbols from date/time, ANTLR grammar already64 // Remove any surrounding '#' symbols from date/time, ANTLR grammar already
65 // ensures date/time starting with '#' symbol will also end with one65 // ensures date/time starting with '#' symbol will also end with one
Source/Libraries/TimeSeriesPlatformLibrary/Samples/AdvancedPublish.cpp+35−11
@@ -33,21 +33,23 @@ using namespace GSF::TimeSeries::Transport; · 32 unmodified lines
33using namespace GSF::FilterExpressions;33using namespace GSF::FilterExpressions;
34 34
35DataPublisherPtr Publisher;35DataPublisherPtr Publisher;
36TimerPtr PublishTimer;36TimerPtr PublishTimer, CompletionTimer;
37vector<DeviceMetadataPtr> DevicesToPublish;37vector<DeviceMetadataPtr> DevicesToPublish;
38vector<MeasurementMetadataPtr> MeasurementsToPublish;38vector<MeasurementMetadataPtr> MeasurementsToPublish;
39vector<PhasorMetadataPtr> PhasorsToPublish;39vector<PhasorMetadataPtr> PhasorsToPublish;
40 40
41bool RunPublisher(uint16_t port);41bool RunPublisher(uint16_t port);
42void DisplayClientConnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID);42void DisplayClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
43void DisplayClientDisconnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID);43void DisplayClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
44void DisplayStatusMessage(DataPublisher* source, const string& message);44void DisplayStatusMessage(DataPublisher* source, const string& message);
45void DisplayErrorMessage(DataPublisher* source, const string& message);45void DisplayErrorMessage(DataPublisher* source, const string& message);
46void HandleTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
47void HandleTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
46 48
47void LoadMetadataToPublish(vector<DeviceMetadataPtr>& deviceMetadata, vector<MeasurementMetadataPtr>& measurementMetadata, vector<PhasorMetadataPtr>& phasorMetadata)49void LoadMetadataToPublish(vector<DeviceMetadataPtr>& deviceMetadata, vector<MeasurementMetadataPtr>& measurementMetadata, vector<PhasorMetadataPtr>& phasorMetadata)
48{50{
49 DeviceMetadataPtr device1Metadata = NewSharedPtr<DeviceMetadata>();51 DeviceMetadataPtr device1Metadata = NewSharedPtr<DeviceMetadata>();
50 const DateTime timestamp = UtcNow();52 const datetime_t timestamp = UtcNow();
51 53
52 // Add a device54 // Add a device
53 device1Metadata->Name = "Test PMU";55 device1Metadata->Name = "Test PMU";
@@ -210,6 +212,11 @@ bool RunPublisher(uint16_t port) · 156 unmodified lines
210 Publisher->RegisterClientDisconnectedCallback(&DisplayClientDisconnected);212 Publisher->RegisterClientDisconnectedCallback(&DisplayClientDisconnected);
211 Publisher->RegisterStatusMessageCallback(&DisplayStatusMessage);213 Publisher->RegisterStatusMessageCallback(&DisplayStatusMessage);
212 Publisher->RegisterErrorMessageCallback(&DisplayErrorMessage);214 Publisher->RegisterErrorMessageCallback(&DisplayErrorMessage);
215 Publisher->RegisterTemporalSubscriptionRequestedCallback(&HandleTemporalSubscriptionRequested);
216 Publisher->RegisterTemporalProcessingIntervalChangeRequestedCallback(&HandleTemporalProcessingIntervalChangeRequested);
217
218 // Enable temporal subscription support
219 Publisher->SetSupportsTemporalSubscriptions(true);
213 220
214 // Load metadata to be used for publication221 // Load metadata to be used for publication
215 LoadMetadataToPublish(DevicesToPublish, MeasurementsToPublish, PhasorsToPublish);222 LoadMetadataToPublish(DevicesToPublish, MeasurementsToPublish, PhasorsToPublish);
@@ -285,18 +292,18 @@ bool RunPublisher(uint16_t port) · 69 unmodified lines
285 return running;292 return running;
286}293}
287 294
288void DisplayClientConnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID)295void DisplayClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
289{296{
290 cout << ">> New Client Connected:" << endl;297 cout << ">> New Client Connected:" << endl;
291 cout << " Subscriber ID: " << ToString(subscriberID) << endl;298 cout << " Subscriber ID: " << ToString(connection->GetSubscriberID()) << endl;
292 cout << " Connection ID: " << connectionID << endl << endl;299 cout << " Connection ID: " << ToString(connection->GetConnectionID()) << endl << endl;
293}300}
294 301
295void DisplayClientDisconnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID)302void DisplayClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
296{303{
297 cout << ">> Client Disconnected:" << endl;304 cout << ">> Client Disconnected:" << endl;
298 cout << " Subscriber ID: " << ToString(subscriberID) << endl;305 cout << " Subscriber ID: " << ToString(connection->GetSubscriberID()) << endl;
299 cout << " Connection ID: " << connectionID << endl << endl;306 cout << " Connection ID: " << ToString(connection->GetConnectionID()) << endl << endl;
300}307}
301 308
302// Callback which is called to display status messages from the subscriber.309// Callback which is called to display status messages from the subscriber.
@@ -309,4 +316,21 @@ void DisplayStatusMessage(DataPublisher* source, const string& message) · 6 unmodified lines
309void DisplayErrorMessage(DataPublisher* source, const string& message)316void DisplayErrorMessage(DataPublisher* source, const string& message)
310{317{
311 cerr << message << endl << endl;318 cerr << message << endl << endl;
312}319}
320
321void HandleTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection)
322{
323 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " has requested a temporal subscription starting at " << ToString(connection->GetStartTimeConstraint()) << endl << endl;
324
325 CompletionTimer = NewSharedPtr<Timer>(1000, [connection](Timer*, void*)
326 {
327 connection->CompleteTemporalSubscription();
328 });
329
330 CompletionTimer->Start();
331}
332
333void HandleTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection)
334{
335 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " has requested to change its temporal processing interval to " << ToString(connection->GetProcessingInterval()) << "ms" << endl << endl;
336}
Source/Libraries/TimeSeriesPlatformLibrary/Samples/FilterExpressionTests.cpp+9−9
@@ -1177,42 +1177,42 @@ int main(int argc, char* argv[]) · 1176 unmodified lines
1177 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-02-04', 2, 'Month')");1177 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-02-04', 2, 'Month')");
1178 1178
1179 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1179 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1180 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 4, 4)));1180 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 4, 4)));
1181 cout << "Test " << ++test << " succeeded..." << endl;1181 cout << "Test " << ++test << " succeeded..." << endl;
1182 1182
1183 // Test 1191183 // Test 119
1184 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#1/31/2019#, 1, 'Day')");1184 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#1/31/2019#, 1, 'Day')");
1185 1185
1186 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1186 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1187 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 2, 1)));1187 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 2, 1)));
1188 cout << "Test " << ++test << " succeeded..." << endl;1188 cout << "Test " << ++test << " succeeded..." << endl;
1189 1189
1190 // Test 1201190 // Test 120
1191 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2019-01-31#, 2, 'Week')");1191 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2019-01-31#, 2, 'Week')");
1192 1192
1193 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1193 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1194 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 2, 14)));1194 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 2, 14)));
1195 cout << "Test " << ++test << " succeeded..." << endl;1195 cout << "Test " << ++test << " succeeded..." << endl;
1196 1196
1197 // Test 1211197 // Test 121
1198 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2019-01-31#, 25, 'Hour')");1198 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2019-01-31#, 25, 'Hour')");
1199 1199
1200 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1200 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1201 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 2, 1), time_duration(1, 0, 0)));1201 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 2, 1), time_duration(1, 0, 0)));
1202 cout << "Test " << ++test << " succeeded..." << endl;1202 cout << "Test " << ++test << " succeeded..." << endl;
1203 1203
1204 // Test 1221204 // Test 122
1205 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2018-12-31 23:58#, 3, 'Minute')");1205 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#2018-12-31 23:58#, 3, 'Minute')");
1206 1206
1207 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1207 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1208 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 1, 1), time_duration(0, 1, 0)));1208 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 1, 1), time_duration(0, 1, 0)));
1209 cout << "Test " << ++test << " succeeded..." << endl;1209 cout << "Test " << ++test << " succeeded..." << endl;
1210 1210
1211 // Test 1231211 // Test 123
1212 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-01-1 00:59', 61, 'Second')");1212 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-01-1 00:59', 61, 'Second')");
1213 1213
1214 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1214 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1215 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 1, 1), time_duration(1, 0, 1)));1215 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 1, 1), time_duration(1, 0, 1)));
1216 cout << "Test " << ++test << " succeeded..." << endl;1216 cout << "Test " << ++test << " succeeded..." << endl;
1217 1217
1218 const float64_t baseFraction = pow(10.0, time_duration::num_fractional_digits());1218 const float64_t baseFraction = pow(10.0, time_duration::num_fractional_digits());
@@ -1222,14 +1222,14 @@ int main(int argc, char* argv[]) · 3 unmodified lines
1222 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-01-1 00:00:59.999', 2, 'Millisecond')");1222 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd('2019-01-1 00:00:59.999', 2, 'Millisecond')");
1223 1223
1224 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1224 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1225 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 1, 1), time_duration(0, 1, 0, fracSecond(1))));1225 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 1, 1), time_duration(0, 1, 0, fracSecond(1))));
1226 cout << "Test " << ++test << " succeeded..." << endl;1226 cout << "Test " << ++test << " succeeded..." << endl;
1227 1227
1228 // Test 1251228 // Test 125
1229 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#1/1/2019 0:0:1.029#, -FramesPerSecond, 'Millisecond')");1229 valueExpression = FilterExpressionParser::Evaluate(dataRow, "DateAdd(#1/1/2019 0:0:1.029#, -FramesPerSecond, 'Millisecond')");
1230 1230
1231 assert(valueExpression->ValueType == ExpressionValueType::DateTime);1231 assert(valueExpression->ValueType == ExpressionValueType::DateTime);
1232 assert(valueExpression->ValueAsDateTime() == DateTime(date(2019, 1, 1), time_duration(0, 0, 0, fracSecond(999))));1232 assert(valueExpression->ValueAsDateTime() == datetime_t(date(2019, 1, 1), time_duration(0, 0, 0, fracSecond(999))));
1233 cout << "Test " << ++test << " succeeded..." << endl;1233 cout << "Test " << ++test << " succeeded..." << endl;
1234 1234
1235 // Test 1261235 // Test 126
@@ -1429,7 +1429,7 @@ int main(int argc, char* argv[]) · 193 unmodified lines
1429 cout << "Test " << ++test << " succeeded..." << endl;1429 cout << "Test " << ++test << " succeeded..." << endl;
1430 1430
1431 // Test 1501431 // Test 150
1432 const DateTime time = ParseTimestamp("2019-02-10T15:55:25.090477Z");1432 const datetime_t time = ParseTimestamp("2019-02-10T15:55:25.090477Z");
1433 const int64_t ticks = ToTicks(time);1433 const int64_t ticks = ToTicks(time);
1434 1434
1435 assert(ticks == 636854109250904770L);1435 assert(ticks == 636854109250904770L);
Source/Libraries/TimeSeriesPlatformLibrary/Samples/SimplePublish.cpp+9−9
@@ -36,8 +36,8 @@ TimerPtr PublishTimer; · 35 unmodified lines
36vector<MeasurementMetadataPtr> MeasurementsToPublish;36vector<MeasurementMetadataPtr> MeasurementsToPublish;
37 37
38bool RunPublisher(uint16_t port);38bool RunPublisher(uint16_t port);
39void DisplayClientConnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID);39void DisplayClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
40void DisplayClientDisconnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID);40void DisplayClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
41void DisplayStatusMessage(DataPublisher* source, const string& message);41void DisplayStatusMessage(DataPublisher* source, const string& message);
42void DisplayErrorMessage(DataPublisher* source, const string& message);42void DisplayErrorMessage(DataPublisher* source, const string& message);
43 43
@@ -168,18 +168,18 @@ bool RunPublisher(uint16_t port) · 124 unmodified lines
168 return running;168 return running;
169}169}
170 170
171void DisplayClientConnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID)171void DisplayClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
172{172{
173 cout << ">> New Client Connected:" << endl;173 cout << ">> New Client Connected:" << endl;
174 cout << " Subscriber ID: " << ToString(subscriberID) << endl;174 cout << " Subscriber ID: " << ToString(connection->GetSubscriberID()) << endl;
175 cout << " Connection ID: " << connectionID << endl << endl;175 cout << " Connection ID: " << ToString(connection->GetConnectionID()) << endl << endl;
176}176}
177 177
178void DisplayClientDisconnected(DataPublisher* source, const Guid& subscriberID, const string& connectionID)178void DisplayClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
179{179{
180 cout << ">> Client Disconnected:" << endl;180 cout << ">> Client Disconnected:" << endl;
181 cout << " Subscriber ID: " << ToString(subscriberID) << endl;181 cout << " Subscriber ID: " << ToString(connection->GetSubscriberID()) << endl;
182 cout << " Connection ID: " << connectionID << endl << endl;182 cout << " Connection ID: " << ToString(connection->GetConnectionID()) << endl << endl;
183}183}
184 184
185// Callback which is called to display status messages from the subscriber.185// Callback which is called to display status messages from the subscriber.
@@ -192,4 +192,4 @@ void DisplayStatusMessage(DataPublisher* source, const string& message) · 6 unmodified lines
192void DisplayErrorMessage(DataPublisher* source, const string& message)192void DisplayErrorMessage(DataPublisher* source, const string& message)
193{193{
194 cerr << message << endl << endl;194 cerr << message << endl << endl;
195}195}
Source/Libraries/TimeSeriesPlatformLibrary/Samples/SubscriberHandler.cpp+1−1
@@ -104,7 +104,7 @@ void SubscriberHandler::DataStartTime(time_t unixSOC, uint16_t milliseconds) · 103 unmodified lines
104 // TODO: This reports timestamp, time_t format, of very first received measurement (if useful)104 // TODO: This reports timestamp, time_t format, of very first received measurement (if useful)
105}105}
106 106
107void SubscriberHandler::DataStartTime(DateTime startTime)107void SubscriberHandler::DataStartTime(datetime_t startTime)
108{108{
109 // TODO: This reports timestamp, ptime format, of very first received measurement (if useful)109 // TODO: This reports timestamp, ptime format, of very first received measurement (if useful)
110}110}
Source/Libraries/TimeSeriesPlatformLibrary/Samples/SubscriberHandler.h+1−1
@@ -41,7 +41,7 @@ protected: · 40 unmodified lines
41 void StatusMessage(const std::string& message) override;41 void StatusMessage(const std::string& message) override;
42 void ErrorMessage(const std::string& message) override;42 void ErrorMessage(const std::string& message) override;
43 void DataStartTime(time_t unixSOC, uint16_t milliseconds) override;43 void DataStartTime(time_t unixSOC, uint16_t milliseconds) override;
44 void DataStartTime(GSF::DateTime startTime) override;44 void DataStartTime(GSF::datetime_t startTime) override;
45 void ReceivedMetadata(const std::vector<uint8_t>& payload) override;45 void ReceivedMetadata(const std::vector<uint8_t>& payload) override;
46 void ReceivedNewMeasurements(const std::vector<GSF::TimeSeries::MeasurementPtr>& measurements) override;46 void ReceivedNewMeasurements(const std::vector<GSF::TimeSeries::MeasurementPtr>& measurements) override;
47 void ParsedMetadata() override;47 void ParsedMetadata() override;
Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataPublisher.cpp+94−34
@@ -36,24 +36,13 @@ using namespace GSF::FilterExpressions; · 35 unmodified lines
36using namespace GSF::TimeSeries;36using namespace GSF::TimeSeries;
37using namespace GSF::TimeSeries::Transport;37using namespace GSF::TimeSeries::Transport;
38 38
39struct SubscriberConnectionInfo
40{
41 const GSF::Guid SubscriberID;
42 const string ConnectionID;
43
44 SubscriberConnectionInfo(const GSF::Guid& subscriberID, string connectionID) :
45 SubscriberID(subscriberID),
46 ConnectionID(std::move(connectionID))
47 {
48 }
49};
50
51DataPublisher::DataPublisher(const TcpEndPoint& endpoint) :39DataPublisher::DataPublisher(const TcpEndPoint& endpoint) :
52 m_nodeID(NewGuid()),40 m_nodeID(NewGuid()),
53 m_securityMode(SecurityMode::None),41 m_securityMode(SecurityMode::None),
54 m_allowMetadataRefresh(true),42 m_allowMetadataRefresh(true),
55 m_allowNaNValueFilter(true),43 m_allowNaNValueFilter(true),
56 m_forceNaNValueFilter(false),44 m_forceNaNValueFilter(false),
45 m_supportsTemporalSubscriptions(false),
57 m_cipherKeyRotationPeriod(60000),46 m_cipherKeyRotationPeriod(60000),
58 m_userData(nullptr),47 m_userData(nullptr),
59 m_disposing(false),48 m_disposing(false),
@@ -116,19 +105,21 @@ void DataPublisher::AcceptConnection(const SubscriberConnectionPtr& connection, · 56 unmodified lines
116 m_subscriberConnectionsLock.unlock();105 m_subscriberConnectionsLock.unlock();
117 106
118 connection->Start();107 connection->Start();
119 DispatchClientConnected(connection->GetSubscriberID(), connection->GetConnectionID());108 DispatchClientConnected(connection);
120 }109 }
121 110
122 StartAccept();111 StartAccept();
123}112}
124 113
114void DataPublisher::ConnectionTerminated(const SubscriberConnectionPtr& connection)
115{
116 DispatchClientDisconnected(connection);
117}
118
125void DataPublisher::RemoveConnection(const SubscriberConnectionPtr& connection)119void DataPublisher::RemoveConnection(const SubscriberConnectionPtr& connection)
126{120{
127 m_subscriberConnectionsLock.lock();121 m_subscriberConnectionsLock.lock();
128 122 m_subscriberConnections.erase(connection);
129 if (m_subscriberConnections.erase(connection))
130 DispatchClientDisconnected(connection->GetSubscriberID(), connection->GetConnectionID());
131
132 m_subscriberConnectionsLock.unlock();123 m_subscriberConnectionsLock.unlock();
133}124}
134 125
@@ -169,16 +160,28 @@ void DataPublisher::DispatchErrorMessage(const string& message) · 34 unmodified lines
169 Dispatch(&ErrorMessageDispatcher, reinterpret_cast<const uint8_t*>(message.c_str()), 0, messageSize);160 Dispatch(&ErrorMessageDispatcher, reinterpret_cast<const uint8_t*>(message.c_str()), 0, messageSize);
170}161}
171 162
172void DataPublisher::DispatchClientConnected(const GSF::Guid& subscriberID, const string& connectionID)163void DataPublisher::DispatchClientConnected(const SubscriberConnectionPtr& connection)
164{
165 SubscriberConnection* connectionReference = &*connection;
166 Dispatch(&ClientConnectedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**));
167}
168
169void DataPublisher::DispatchClientDisconnected(const SubscriberConnectionPtr& connection)
170{
171 SubscriberConnection* connectionReference = &*connection;
172 Dispatch(&ClientDisconnectedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**));
173}
174
175void DataPublisher::DispatchTemporalSubscriptionRequested(const SubscriberConnectionPtr& connection)
173{176{
174 SubscriberConnectionInfo* data = new SubscriberConnectionInfo(subscriberID, connectionID);177 SubscriberConnection* connectionReference = &*connection;
175 Dispatch(&ClientConnectedDispatcher, reinterpret_cast<uint8_t*>(&data), 0, sizeof(SubscriberConnectionInfo**));178 Dispatch(&TemporalSubscriptionRequestedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**));
176}179}
177 180
178void DataPublisher::DispatchClientDisconnected(const GSF::Guid& subscriberID, const std::string& connectionID)181void DataPublisher::DispatchTemporalProcessingIntervalChangeRequested(const SubscriberConnectionPtr& connection)
179{182{
180 SubscriberConnectionInfo* data = new SubscriberConnectionInfo(subscriberID, connectionID);183 SubscriberConnection* connectionReference = &*connection;
181 Dispatch(&ClientDisconnectedDispatcher, reinterpret_cast<uint8_t*>(&data), 0, sizeof(SubscriberConnectionInfo**));184 Dispatch(&TemporalProcessingIntervalChangeRequestedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**));
182}185}
183 186
184// Dispatcher function for status messages. Decodes the message and provides it to the user via the status message callback.187// Dispatcher function for status messages. Decodes the message and provides it to the user via the status message callback.
@@ -207,32 +210,56 @@ void DataPublisher::ErrorMessageDispatcher(DataPublisher* source, const vector<u · 22 unmodified lines
207 210
208void DataPublisher::ClientConnectedDispatcher(DataPublisher* source, const vector<uint8_t>& buffer)211void DataPublisher::ClientConnectedDispatcher(DataPublisher* source, const vector<uint8_t>& buffer)
209{212{
210 SubscriberConnectionInfo* data = *reinterpret_cast<SubscriberConnectionInfo**>(const_cast<uint8_t*>(&buffer[0]));213 SubscriberConnection* connection = *reinterpret_cast<SubscriberConnection**>(const_cast<uint8_t*>(&buffer[0]));
211 214
212 if (source != nullptr)215 if (source != nullptr)
213 {216 {
214 const SubscriberConnectionCallback clientConnectedCallback = source->m_clientConnectedCallback;217 const SubscriberConnectionCallback clientConnectedCallback = source->m_clientConnectedCallback;
215 218
216 if (clientConnectedCallback != nullptr)219 if (clientConnectedCallback != nullptr)
217 clientConnectedCallback(source, data->SubscriberID, data->ConnectionID);220 clientConnectedCallback(source, connection->GetReference());
218 }221 }
219
220 delete data;
221}222}
222 223
223void DataPublisher::ClientDisconnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer)224void DataPublisher::ClientDisconnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer)
224{225{
225 SubscriberConnectionInfo* data = *reinterpret_cast<SubscriberConnectionInfo**>(const_cast<uint8_t*>(&buffer[0]));226 SubscriberConnection* connection = *reinterpret_cast<SubscriberConnection**>(const_cast<uint8_t*>(&buffer[0]));
226 227
227 if (source != nullptr)228 if (source != nullptr)
228 {229 {
229 const SubscriberConnectionCallback clientDisconnectedCallback = source->m_clientDisconnectedCallback;230 const SubscriberConnectionCallback clientDisconnectedCallback = source->m_clientDisconnectedCallback;
230 231
231 if (clientDisconnectedCallback != nullptr)232 if (clientDisconnectedCallback != nullptr)
232 clientDisconnectedCallback(source, data->SubscriberID, data->ConnectionID);233 clientDisconnectedCallback(source, connection->GetReference());
234
235 source->RemoveConnection(connection->GetReference());
236 }
237}
238
239void DataPublisher::TemporalSubscriptionRequestedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer)
240{
241 SubscriberConnection* connection = *reinterpret_cast<SubscriberConnection**>(const_cast<uint8_t*>(&buffer[0]));
242
243 if (source != nullptr)
244 {
245 const SubscriberConnectionCallback temporalSubscriptionRequestedCallback = source->m_temporalSubscriptionRequestedCallback;
246
247 if (temporalSubscriptionRequestedCallback != nullptr)
248 temporalSubscriptionRequestedCallback(source, connection->GetReference());
233 }249 }
250}
251
252void DataPublisher::TemporalProcessingIntervalChangeRequestedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer)
253{
254 SubscriberConnection* connection = *reinterpret_cast<SubscriberConnection**>(const_cast<uint8_t*>(&buffer[0]));
255
256 if (source != nullptr)
257 {
258 const SubscriberConnectionCallback temporalProcessingIntervalChangeRequestedCallback = source->m_temporalProcessingIntervalChangeRequestedCallback;
234 259
235 delete data;260 if (temporalProcessingIntervalChangeRequestedCallback != nullptr)
261 temporalProcessingIntervalChangeRequestedCallback(source, connection->GetReference());
262 }
236}263}
237 264
238int32_t DataPublisher::GetColumnIndex(const GSF::Data::DataTablePtr& table, const std::string& columnName)265int32_t DataPublisher::GetColumnIndex(const GSF::Data::DataTablePtr& table, const std::string& columnName)
@@ -683,14 +710,27 @@ vector<MeasurementMetadataPtr> DataPublisher::FilterMetadata(const string& filte · 444 unmodified lines
683 710
684void DataPublisher::PublishMeasurements(const vector<Measurement>& measurements)711void DataPublisher::PublishMeasurements(const vector<Measurement>& measurements)
685{712{
686 for (const auto& connection : m_subscriberConnections)713 vector<MeasurementPtr> measurementPtrs;
687 connection->PublishMeasurements(measurements);714
715 measurementPtrs.reserve(measurements.size());
716
717 for (const auto& measurement : measurements)
718 measurementPtrs.push_back(ToPtr(measurement));
719
720 PublishMeasurements(measurementPtrs);
688}721}
689 722
690void DataPublisher::PublishMeasurements(const vector<MeasurementPtr>& measurements)723void DataPublisher::PublishMeasurements(const vector<MeasurementPtr>& measurements)
691{724{
725 m_subscriberConnectionsLock.lock();
726
692 for (const auto& connection : m_subscriberConnections)727 for (const auto& connection : m_subscriberConnections)
693 connection->PublishMeasurements(measurements);728 {
729 if (connection->GetIsSubscribed() && !connection->GetIsTemporalSubscription())
730 connection->PublishMeasurements(measurements);
731 }
732
733 m_subscriberConnectionsLock.unlock();
694}734}
695 735
696const GSF::Guid& DataPublisher::GetNodeID() const736const GSF::Guid& DataPublisher::GetNodeID() const
@@ -743,6 +783,16 @@ void DataPublisher::SetNaNValueFilterForced(bool forced) · 46 unmodified lines
743 m_forceNaNValueFilter = forced;783 m_forceNaNValueFilter = forced;
744}784}
745 785
786bool DataPublisher::GetSupportsTemporalSubscriptions() const
787{
788 return m_supportsTemporalSubscriptions;
789}
790
791void DataPublisher::SetSupportsTemporalSubscriptions(bool value)
792{
793 m_supportsTemporalSubscriptions = value;
794}
795
746uint32_t DataPublisher::GetCipherKeyRotationPeriod() const796uint32_t DataPublisher::GetCipherKeyRotationPeriod() const
747{797{
748 return m_cipherKeyRotationPeriod;798 return m_cipherKeyRotationPeriod;
@@ -823,4 +873,14 @@ void DataPublisher::RegisterClientConnectedCallback(const SubscriberConnectionCa · 74 unmodified lines
823void DataPublisher::RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback)873void DataPublisher::RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback)
824{874{
825 m_clientDisconnectedCallback = clientDisconnectedCallback;875 m_clientDisconnectedCallback = clientDisconnectedCallback;
826}876}
877
878void DataPublisher::RegisterTemporalSubscriptionRequestedCallback(const SubscriberConnectionCallback& temporalSubscriptionRequestedCallback)
879{
880 m_temporalSubscriptionRequestedCallback = temporalSubscriptionRequestedCallback;
881}
882
883void DataPublisher::RegisterTemporalProcessingIntervalChangeRequestedCallback(const SubscriberConnectionCallback& temporalProcessingIntervalChangeRequestedCallback)
884{
885 m_temporalProcessingIntervalChangeRequestedCallback = temporalProcessingIntervalChangeRequestedCallback;
886}
Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataPublisher.h+34−13
@@ -44,12 +44,13 @@ namespace Transport · 43 unmodified lines
44{44{
45 class DataPublisher : public EnableSharedThisPtr<DataPublisher> // NOLINT45 class DataPublisher : public EnableSharedThisPtr<DataPublisher> // NOLINT
46 {46 {
47 private:47 public:
48 // Function pointer types48 // Function pointer types
49 typedef std::function<void(DataPublisher*, const std::vector<uint8_t>&)> DispatcherFunction;49 typedef std::function<void(DataPublisher*, const std::vector<uint8_t>&)> DispatcherFunction;
50 typedef std::function<void(DataPublisher*, const std::string&)> MessageCallback;50 typedef std::function<void(DataPublisher*, const std::string&)> MessageCallback;
51 typedef std::function<void(DataPublisher*, const GSF::Guid&, const std::string&)> SubscriberConnectionCallback;51 typedef std::function<void(DataPublisher*, const SubscriberConnectionPtr&)> SubscriberConnectionCallback;
52 52
53 private:
53 // Structure used to dispatch54 // Structure used to dispatch
54 // callbacks on the callback thread.55 // callbacks on the callback thread.
55 struct CallbackDispatcher56 struct CallbackDispatcher
@@ -70,6 +71,7 @@ namespace Transport · 14 unmodified lines
70 bool m_allowMetadataRefresh;71 bool m_allowMetadataRefresh;
71 bool m_allowNaNValueFilter;72 bool m_allowNaNValueFilter;
72 bool m_forceNaNValueFilter;73 bool m_forceNaNValueFilter;
74 bool m_supportsTemporalSubscriptions;
73 uint32_t m_cipherKeyRotationPeriod;75 uint32_t m_cipherKeyRotationPeriod;
74 void* m_userData;76 void* m_userData;
75 bool m_disposing;77 bool m_disposing;
@@ -93,6 +95,7 @@ namespace Transport · 17 unmodified lines
93 // Command channel handlers95 // Command channel handlers
94 void StartAccept();96 void StartAccept();
95 void AcceptConnection(const SubscriberConnectionPtr& connection, const ErrorCode& error);97 void AcceptConnection(const SubscriberConnectionPtr& connection, const ErrorCode& error);
98 void ConnectionTerminated(const SubscriberConnectionPtr& connection);
96 void RemoveConnection(const SubscriberConnectionPtr& connection);99 void RemoveConnection(const SubscriberConnectionPtr& connection);
97 100
98 // Callbacks101 // Callbacks
@@ -100,19 +103,25 @@ namespace Transport · 1 unmodified line
100 MessageCallback m_errorMessageCallback;103 MessageCallback m_errorMessageCallback;
101 SubscriberConnectionCallback m_clientConnectedCallback;104 SubscriberConnectionCallback m_clientConnectedCallback;
102 SubscriberConnectionCallback m_clientDisconnectedCallback;105 SubscriberConnectionCallback m_clientDisconnectedCallback;
106 SubscriberConnectionCallback m_temporalSubscriptionRequestedCallback;
107 SubscriberConnectionCallback m_temporalProcessingIntervalChangeRequestedCallback;
103 108
104 // Dispatchers109 // Dispatchers
105 void Dispatch(const DispatcherFunction& function);110 void Dispatch(const DispatcherFunction& function);
106 void Dispatch(const DispatcherFunction& function, const uint8_t* data, uint32_t offset, uint32_t length);111 void Dispatch(const DispatcherFunction& function, const uint8_t* data, uint32_t offset, uint32_t length);
107 void DispatchStatusMessage(const std::string& message);112 void DispatchStatusMessage(const std::string& message);
108 void DispatchErrorMessage(const std::string& message);113 void DispatchErrorMessage(const std::string& message);
109 void DispatchClientConnected(const GSF::Guid& subscriberID, const std::string& connectionID);114 void DispatchClientConnected(const SubscriberConnectionPtr& connection);
110 void DispatchClientDisconnected(const GSF::Guid& subscriberID, const std::string& connectionID);115 void DispatchClientDisconnected(const SubscriberConnectionPtr& connection);
116 void DispatchTemporalSubscriptionRequested(const SubscriberConnectionPtr& connection);
117 void DispatchTemporalProcessingIntervalChangeRequested(const SubscriberConnectionPtr& connection);
111 118
112 static void StatusMessageDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);119 static void StatusMessageDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
113 static void ErrorMessageDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);120 static void ErrorMessageDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
114 static void ClientConnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);121 static void ClientConnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
115 static void ClientDisconnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);122 static void ClientDisconnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
123 static void TemporalSubscriptionRequestedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
124 static void TemporalProcessingIntervalChangeRequestedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer);
116 static int32_t GetColumnIndex(const GSF::Data::DataTablePtr& table, const std::string& columnName);125 static int32_t GetColumnIndex(const GSF::Data::DataTablePtr& table, const std::string& columnName);
117 public:126 public:
118 // Creates a new instance of the data publisher.127 // Creates a new instance of the data publisher.
@@ -123,14 +132,22 @@ namespace Transport · 4 unmodified lines
123 // tied up by the publisher.132 // tied up by the publisher.
124 ~DataPublisher();133 ~DataPublisher();
125 134
126 // Define metadata from existing metadata tables135 // Defines metadata from existing metadata records
127 void DefineMetadata(const std::vector<DeviceMetadataPtr>& deviceMetadata, const std::vector<MeasurementMetadataPtr>& measurementMetadata, const std::vector<PhasorMetadataPtr>& phasorMetadata, int32_t versionNumber = 0);136 void DefineMetadata(const std::vector<DeviceMetadataPtr>& deviceMetadata, const std::vector<MeasurementMetadataPtr>& measurementMetadata, const std::vector<PhasorMetadataPtr>& phasorMetadata, int32_t versionNumber = 0);
128 137
129 // Define metadata from an existing dataset138 // Defines metadata from an existing dataset
130 void DefineMetadata(const GSF::Data::DataSetPtr& metadata);139 void DefineMetadata(const GSF::Data::DataSetPtr& metadata);
131 140
141 // Gets primary metadata. This dataset contains all the normalized metadata tables that define
142 // the available detail about the data points that can be subscribed to by clients.
132 const GSF::Data::DataSetPtr& GetMetadata() const;143 const GSF::Data::DataSetPtr& GetMetadata() const;
144
145 // Gets filtering metadata. This dataset, derived from primary metadata, contains a flattened
146 // table used to subscribe to a filtered set of points with an expression, e.g.:
147 // FILTER ActiveMeasurements WHERE SignalType LIKE '%PHA'
133 const GSF::Data::DataSetPtr& GetFilteringMetadata() const;148 const GSF::Data::DataSetPtr& GetFilteringMetadata() const;
149
150 // Filters primary MeasurementDetail metadata returning values as measurement metadata records
134 std::vector<MeasurementMetadataPtr> FilterMetadata(const std::string& filterExpression) const;151 std::vector<MeasurementMetadataPtr> FilterMetadata(const std::string& filterExpression) const;
135 152
136 void PublishMeasurements(const std::vector<Measurement>& measurements);153 void PublishMeasurements(const std::vector<Measurement>& measurements);
@@ -154,6 +171,9 @@ namespace Transport · 17 unmodified lines
154 bool IsNaNValueFilterForced() const;171 bool IsNaNValueFilterForced() const;
155 void SetNaNValueFilterForced(bool forced);172 void SetNaNValueFilterForced(bool forced);
156 173
174 bool GetSupportsTemporalSubscriptions() const;
175 void SetSupportsTemporalSubscriptions(bool value);
176
157 uint32_t GetCipherKeyRotationPeriod() const;177 uint32_t GetCipherKeyRotationPeriod() const;
158 void SetCipherKeyRotationPeriod(uint32_t period);178 void SetCipherKeyRotationPeriod(uint32_t period);
159 179
@@ -169,17 +189,18 @@ namespace Transport · 9 unmodified lines
169 // Callback registration189 // Callback registration
170 //190 //
171 // Callback functions are defined with the following signatures:191 // Callback functions are defined with the following signatures:
172 // void ProcessStatusMessage(DataPublisher*, const string& message)192 // void ProcessStatusMessage(DataPublisher* source, const string& message)
173 // void ProcessErrorMessage(DataPublisher*, const string& message)193 // void ProcessErrorMessage(DataPublisher* source, const string& message)
174 // void ProcessClientConnected(DataPublisher*, const GSF::Guid& subscriberID, const string& connectionID);194 // void ProcessClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
175 // void ProcessClientDisconnected(DataPublisher*, const GSF::Guid& subscriberID, const string& connectionID);195 // void ProcessClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
196 // void ProcessTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
197 // void ProcessTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
176 void RegisterStatusMessageCallback(const MessageCallback& statusMessageCallback);198 void RegisterStatusMessageCallback(const MessageCallback& statusMessageCallback);
177 void RegisterErrorMessageCallback(const MessageCallback& errorMessageCallback);199 void RegisterErrorMessageCallback(const MessageCallback& errorMessageCallback);
178 void RegisterClientConnectedCallback(const SubscriberConnectionCallback& clientConnectedCallback);200 void RegisterClientConnectedCallback(const SubscriberConnectionCallback& clientConnectedCallback);
179 void RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback);201 void RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback);
180 202 void RegisterTemporalSubscriptionRequestedCallback(const SubscriberConnectionCallback& temporalSubscriptionRequestedCallback);
181 //static std::string DecodeClientString(const SubscriberConnectionPtr& connection, const uint8_t* data, uint32_t offset, uint32_t length);203 void RegisterTemporalProcessingIntervalChangeRequestedCallback(const SubscriberConnectionCallback& temporalProcessingIntervalChangeRequestedCallback);
182 //static std::vector<uint8_t> EncodeClientString(const SubscriberConnectionPtr& connection, const std::string& value);
183 204
184 friend class SubscriberConnection;205 friend class SubscriberConnection;
185 };206 };
Source/Libraries/TimeSeriesPlatformLibrary/Transport/DataSubscriber.h+10−9
@@ -134,7 +134,7 @@ namespace Transport · 133 unmodified lines
134 134
135 class DataSubscriber // NOLINT135 class DataSubscriber // NOLINT
136 {136 {
137 private:137 public:
138 // Function pointer types138 // Function pointer types
139 typedef std::function<void(DataSubscriber*, const std::vector<uint8_t>&)> DispatcherFunction;139 typedef std::function<void(DataSubscriber*, const std::vector<uint8_t>&)> DispatcherFunction;
140 typedef std::function<void(DataSubscriber*, const std::string&)> MessageCallback;140 typedef std::function<void(DataSubscriber*, const std::string&)> MessageCallback;
@@ -144,6 +144,7 @@ namespace Transport · 3 unmodified lines
144 typedef std::function<void(DataSubscriber*)> ConfigurationChangedCallback;144 typedef std::function<void(DataSubscriber*)> ConfigurationChangedCallback;
145 typedef std::function<void(DataSubscriber*)> ConnectionTerminatedCallback;145 typedef std::function<void(DataSubscriber*)> ConnectionTerminatedCallback;
146 146
147 private:
147 // Structure used to dispatch148 // Structure used to dispatch
148 // callbacks on the callback thread.149 // callbacks on the callback thread.
149 struct CallbackDispatcher150 struct CallbackDispatcher
@@ -263,14 +264,14 @@ namespace Transport · 113 unmodified lines
263 // Callback registration264 // Callback registration
264 //265 //
265 // Callback functions are defined with the following signatures:266 // Callback functions are defined with the following signatures:
266 // void ProcessStatusMessage(DataSubscriber*, const string& message)267 // void ProcessStatusMessage(DataSubscriber* source, const string& message)
267 // void ProcessErrorMessage(DataSubscriber*, const string& message)268 // void ProcessErrorMessage(DataSubscriber* source, const string& message)
268 // void ProcessDataStartTime(DataSubscriber*, int64_t startTime)269 // void ProcessDataStartTime(DataSubscriber* source, int64_t startTime)
269 // void ProcessMetadata(DataSubscriber*, const vector<uint8_t>& metadata)270 // void ProcessMetadata(DataSubscriber* source, const vector<uint8_t>& metadata)
270 // void ProcessNewMeasurements(DataSubscriber*, const vector<MeasurementPtr>& newMeasurements)271 // void ProcessNewMeasurements(DataSubscriber* source, const vector<MeasurementPtr>& newMeasurements)
271 // void ProcessProcessingComplete(DataSubscriber*, const string& message)272 // void ProcessProcessingComplete(DataSubscriber* source, const string& message)
272 // void ProcessConfigurationChanged(DataSubscriber*)273 // void ProcessConfigurationChanged(DataSubscriber* source)
273 // void ProcessConnectionTerminated(DataSubscriber*)274 // void ProcessConnectionTerminated(DataSubscriber* source)
274 //275 //
275 // Metadata is provided to the user as zlib-compressed XML,276 // Metadata is provided to the user as zlib-compressed XML,
276 // and must be decompressed and interpreted before it can be used.277 // and must be decompressed and interpreted before it can be used.
Source/Libraries/TimeSeriesPlatformLibrary/Transport/PublisherInstance.cpp+32−8
@@ -57,16 +57,28 @@ void PublisherInstance::HandleErrorMessage(DataPublisher* source, const string& · 56 unmodified lines
57 instance->ErrorMessage(message);57 instance->ErrorMessage(message);
58}58}
59 59
60void PublisherInstance::HandleClientConnected(DataPublisher* source, const GSF::Guid& subscriberID, const std::string& connectionID)60void PublisherInstance::HandleClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
61{61{
62 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());62 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());
63 instance->ClientConnected(subscriberID, connectionID);63 instance->ClientConnected(connection);
64}64}
65 65
66void PublisherInstance::HandleClientDisconnected(DataPublisher* source, const GSF::Guid& subscriberID, const std::string& connectionID)66void PublisherInstance::HandleClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection)
67{67{
68 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());68 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());
69 instance->ClientDisconnected(subscriberID, connectionID);69 instance->ClientDisconnected(connection);
70}
71
72void PublisherInstance::HandleTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection)
73{
74 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());
75 instance->TemporalSubscriptionRequested(connection);
76}
77
78void PublisherInstance::HandleTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection)
79{
80 PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData());
81 instance->TemporalProcessingIntervalChangeRequested(connection);
70}82}
71 83
72void PublisherInstance::StatusMessage(const string& message)84void PublisherInstance::StatusMessage(const string& message)
@@ -79,14 +91,24 @@ void PublisherInstance::ErrorMessage(const string& message) · 6 unmodified lines
79 cerr << message << endl << endl;91 cerr << message << endl << endl;
80}92}
81 93
82void PublisherInstance::ClientConnected(const GSF::Guid& subscriberID, const string& connectionID)94void PublisherInstance::ClientConnected(const SubscriberConnectionPtr& connection)
95{
96 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " connected..." << endl << endl;
97}
98
99void PublisherInstance::ClientDisconnected(const SubscriberConnectionPtr& connection)
100{
101 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " disconnected..." << endl << endl;
102}
103
104void PublisherInstance::TemporalSubscriptionRequested(const SubscriberConnectionPtr& connection)
83{105{
84 cout << "Client \"" << connectionID << "\" with subscriber ID " << ToString(subscriberID) << " connected..." << endl << endl;106 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " has requested a temporal subscription starting at " << ToString(connection->GetStartTimeConstraint()) << endl << endl;
85}107}
86 108
87void PublisherInstance::ClientDisconnected(const GSF::Guid& subscriberID, const std::string& connectionID)109void PublisherInstance::TemporalProcessingIntervalChangeRequested(const SubscriberConnectionPtr& connection)
88{110{
89 cout << "Client \"" << connectionID << "\" with subscriber ID " << ToString(subscriberID) << " disconnected..." << endl << endl;111 cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " has requested to change its temporal processing interval to " << ToString(connection->GetProcessingInterval()) << "ms" << endl << endl;
90}112}
91 113
92void PublisherInstance::Initialize()114void PublisherInstance::Initialize()
@@ -96,6 +118,8 @@ void PublisherInstance::Initialize() · 3 unmodified lines
96 m_publisher.RegisterErrorMessageCallback(&HandleErrorMessage);118 m_publisher.RegisterErrorMessageCallback(&HandleErrorMessage);
97 m_publisher.RegisterClientConnectedCallback(&HandleClientConnected);119 m_publisher.RegisterClientConnectedCallback(&HandleClientConnected);
98 m_publisher.RegisterClientDisconnectedCallback(&HandleClientDisconnected);120 m_publisher.RegisterClientDisconnectedCallback(&HandleClientDisconnected);
121 m_publisher.RegisterTemporalSubscriptionRequestedCallback(&HandleTemporalSubscriptionRequested);
122 m_publisher.RegisterTemporalProcessingIntervalChangeRequestedCallback(&HandleTemporalProcessingIntervalChangeRequested);
99 123
100 m_initialized = true;124 m_initialized = true;
101}125}
Source/Libraries/TimeSeriesPlatformLibrary/Transport/PublisherInstance.h+8−4
@@ -43,14 +43,18 @@ namespace Transport · 42 unmodified lines
43 // Internal subscription event handlers43 // Internal subscription event handlers
44 static void HandleStatusMessage(DataPublisher* source, const std::string& message);44 static void HandleStatusMessage(DataPublisher* source, const std::string& message);
45 static void HandleErrorMessage(DataPublisher* source, const std::string& message);45 static void HandleErrorMessage(DataPublisher* source, const std::string& message);
46 static void HandleClientConnected(DataPublisher* source, const Guid& subscriberID, const std::string& connectionID);46 static void HandleClientConnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
47 static void HandleClientDisconnected(DataPublisher* source, const Guid& subscriberID, const std::string& connectionID);47 static void HandleClientDisconnected(DataPublisher* source, const SubscriberConnectionPtr& connection);
48 static void HandleTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
49 static void HandleTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection);
48 50
49 protected:51 protected:
50 virtual void StatusMessage(const std::string& message); // Defaults output to cout52 virtual void StatusMessage(const std::string& message); // Defaults output to cout
51 virtual void ErrorMessage(const std::string& message); // Defaults output to cerr53 virtual void ErrorMessage(const std::string& message); // Defaults output to cerr
52 virtual void ClientConnected(const Guid& subscriberID, const std::string& connectionID);54 virtual void ClientConnected(const SubscriberConnectionPtr& connection);
53 virtual void ClientDisconnected(const Guid& subscriberID, const std::string& connectionID);55 virtual void ClientDisconnected(const SubscriberConnectionPtr& connection);
56 virtual void TemporalSubscriptionRequested(const SubscriberConnectionPtr& connection);
57 virtual void TemporalProcessingIntervalChangeRequested(const SubscriberConnectionPtr& connection);
54 58
55 public:59 public:
56 PublisherInstance(uint16_t port, bool ipV6);60 PublisherInstance(uint16_t port, bool ipV6);
Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberConnection.cpp+114−58
@@ -48,6 +48,9 @@ SubscriberConnection::SubscriberConnection(DataPublisherPtr parent, IOContext& c · 47 unmodified lines
48 m_subscriberID(NewGuid()),48 m_subscriberID(NewGuid()),
49 m_operationalModes(OperationalModes::NoFlags),49 m_operationalModes(OperationalModes::NoFlags),
50 m_encoding(OperationalEncoding::UTF8),50 m_encoding(OperationalEncoding::UTF8),
51 m_startTimeConstraint(DateTime::MaxValue),
52 m_stopTimeConstraint(DateTime::MaxValue),
53 m_processingInterval(-1),
51 m_usePayloadCompression(false),54 m_usePayloadCompression(false),
52 m_useCompactMeasurementFormat(true),55 m_useCompactMeasurementFormat(true),
53 m_includeTime(true),56 m_includeTime(true),
@@ -80,6 +83,11 @@ const DataPublisherPtr& SubscriberConnection::GetParent() const · 26 unmodified lines
80 return m_parent;83 return m_parent;
81}84}
82 85
86SubscriberConnectionPtr SubscriberConnection::GetReference()
87{
88 return shared_from_this();
89}
90
83TcpSocket& SubscriberConnection::CommandChannelSocket()91TcpSocket& SubscriberConnection::CommandChannelSocket()
84{92{
85 return m_commandChannelSocket;93 return m_commandChannelSocket;
@@ -126,6 +134,43 @@ uint32_t SubscriberConnection::GetEncoding() const · 40 unmodified lines
126 return m_encoding;134 return m_encoding;
127}135}
128 136
137bool SubscriberConnection::GetIsTemporalSubscription() const
138{
139 return m_startTimeConstraint < DateTime::MaxValue;
140}
141
142const GSF::datetime_t& SubscriberConnection::GetStartTimeConstraint() const
143{
144 return m_startTimeConstraint;
145}
146
147void SubscriberConnection::SetStartTimeConstraint(const GSF::datetime_t& value)
148{
149 m_startTimeConstraint = value;
150}
151
152const GSF::datetime_t& SubscriberConnection::GetStopTimeConstraint() const
153{
154 return m_stopTimeConstraint;
155}
156
157void SubscriberConnection::SetStopTimeConstraint(const GSF::datetime_t& value)
158{
159 m_stopTimeConstraint = value;
160}
161
162int32_t SubscriberConnection::GetProcessingInterval() const
163{
164 return m_processingInterval;
165}
166
167void SubscriberConnection::SetProcessingInterval(int32_t value)
168{
169 m_processingInterval = value;
170 m_parent->DispatchTemporalProcessingIntervalChangeRequested(shared_from_this());
171 m_parent->DispatchStatusMessage(m_connectionID + " was assigned a new processing interval of " + ToString(value) + ".");
172}
173
129bool SubscriberConnection::GetUsePayloadCompression() const174bool SubscriberConnection::GetUsePayloadCompression() const
130{175{
131 return m_usePayloadCompression;176 return m_usePayloadCompression;
@@ -313,50 +358,7 @@ void SubscriberConnection::Stop() · 181 unmodified lines
313 m_pingTimer.Stop();358 m_pingTimer.Stop();
314 m_commandChannelSocket.shutdown(socket_base::shutdown_both);359 m_commandChannelSocket.shutdown(socket_base::shutdown_both);
315 m_commandChannelSocket.cancel();360 m_commandChannelSocket.cancel();
316 m_parent->RemoveConnection(shared_from_this());361 m_parent->ConnectionTerminated(shared_from_this());
317}
318
319void SubscriberConnection::PublishMeasurements(const vector<Measurement>& measurements)
320{
321 if (measurements.empty() || !m_isSubscribed)
322 return;
323
324 if (!m_startTimeSent)
325 m_startTimeSent = SendDataStartTime(measurements[0].Timestamp);
326
327 // TODO: Consider queuing measurements for processing
328
329 CompactMeasurement serializer(m_signalIndexCache, m_baseTimeOffsets, m_includeTime, m_useCompactMeasurementFormat);
330 vector<uint8_t> packet, buffer;
331 int32_t count = 0;
332
333 packet.reserve(MaxPacketSize);
334 buffer.reserve(16);
335
336 for (size_t i = 0; i < measurements.size(); i++)
337 {
338 const Measurement& measurement = measurements[i];
339 const uint16_t runtimeID = m_signalIndexCache->GetSignalIndex(measurement.SignalID);
340
341 if (runtimeID == UInt16::MaxValue)
342 continue;
343
344 const uint32_t length = serializer.SerializeMeasurement(measurement, buffer, runtimeID);
345
346 if (packet.size() + length > MaxPacketSize)
347 {
348 PublishDataPacket(packet, count);
349 packet.clear();
350 count = 0;
351 }
352
353 WriteBytes(packet, buffer);
354 buffer.clear();
355 count++;
356 }
357
358 if (count > 0)
359 PublishDataPacket(packet, count);
360}362}
361 363
362void SubscriberConnection::PublishMeasurements(const vector<MeasurementPtr>& measurements)364void SubscriberConnection::PublishMeasurements(const vector<MeasurementPtr>& measurements)
@@ -402,6 +404,11 @@ void SubscriberConnection::PublishMeasurements(const vector<MeasurementPtr>& mea · 39 unmodified lines
402 PublishDataPacket(packet, count);404 PublishDataPacket(packet, count);
403}405}
404 406
407void SubscriberConnection::CompleteTemporalSubscription()
408{
409 SendResponse(ServerResponse::ProcessingComplete, ServerCommand::Subscribe, ToString(m_parent->GetNodeID()));
410}
411
405void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length)412void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length)
406{413{
407 try414 try
@@ -441,6 +448,24 @@ void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length) · 33 unmodified lines
441 if (TryGetValue(settings, "requestNaNValueFilter", setting))448 if (TryGetValue(settings, "requestNaNValueFilter", setting))
442 SetIsNaNFiltered(ParseBoolean(setting));449 SetIsNaNFiltered(ParseBoolean(setting));
443 450
451 if (TryGetValue(settings, "startTimeConstraint", setting))
452 TryParseTimestamp(setting.c_str(), m_startTimeConstraint, DateTime::MaxValue);
453
454 if (TryGetValue(settings, "startTimeConstraint", setting))
455 TryParseTimestamp(setting.c_str(), m_startTimeConstraint, DateTime::MaxValue);
456
457 if (TryGetValue(settings, "processingInterval", setting) && !setting.empty())
458 TryParseInt32(setting, m_processingInterval, -1);
459
460 if (GetIsTemporalSubscription())
461 {
462 if (!m_parent->GetSupportsTemporalSubscriptions())
463 throw PublisherException("Publisher does not temporal subscriptions");
464
465 if (m_startTimeConstraint > m_stopTimeConstraint)
466 throw PublisherException("Specified stop time of requested temporal subscription precedes start time");
467 }
468
444 SetUsePayloadCompression(usePayloadCompression);469 SetUsePayloadCompression(usePayloadCompression);
445 SetUseCompactMeasurementFormat(useCompactMeasurementFormat);470 SetUseCompactMeasurementFormat(useCompactMeasurementFormat);
446 471
@@ -518,36 +543,48 @@ void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length) · 71 unmodified lines
518 SetIsSubscribed(true);543 SetIsSubscribed(true);
519 SendResponse(ServerResponse::Succeeded, ServerCommand::Subscribe, message);544 SendResponse(ServerResponse::Succeeded, ServerCommand::Subscribe, message);
520 m_parent->DispatchStatusMessage(message);545 m_parent->DispatchStatusMessage(message);
546
547 if (GetIsTemporalSubscription())
548 m_parent->DispatchTemporalSubscriptionRequested(shared_from_this());
521 }549 }
522 else550 else
523 {551 {
524 const string message = byteLength > 0 ?552 HandleSubscribeFailure(byteLength > 0 ?
525 "Not enough buffer was provided to parse client data subscription." :553 "Not enough buffer was provided to parse client data subscription." :
526 "Cannot initialize client data subscription without a connection string.";554 "Cannot initialize client data subscription without a connection string.");
527
528 SendResponse(ServerResponse::Failed, ServerCommand::Subscribe, message);
529 m_parent->DispatchErrorMessage(message);
530 } 555 }
531 } 556 }
532 }557 }
533 else558 else
534 {559 {
535 const string message = "Not enough buffer was provided to parse client data subscription.";560 HandleSubscribeFailure("Not enough buffer was provided to parse client data subscription.");
536 SendResponse(ServerResponse::Failed, ServerCommand::Subscribe, message);
537 m_parent->DispatchErrorMessage(message);
538 }561 }
539 }562 }
540 catch (const std::exception& ex)563 catch (const PublisherException& ex)
541 {564 {
542 const string message = "Failed to process client data subscription due to exception: " + string(ex.what());565 HandleSubscribeFailure("Failed to process client data subscription due to exception: " + string(ex.what()));
543 SendResponse(ServerResponse::Failed, ServerCommand::Subscribe, message);566 }
544 m_parent->DispatchErrorMessage(message);567 catch (...)
568 {
569 HandleSubscribeFailure("Failed to process client data subscription due to exception: " + boost::current_exception_diagnostic_information(true));
545 }570 }
546}571}
547 572
573void SubscriberConnection::HandleSubscribeFailure(const std::string& message)
574{
575 SendResponse(ServerResponse::Failed, ServerCommand::Subscribe, message);
576 m_parent->DispatchErrorMessage(message);
577
578 if (GetIsTemporalSubscription())
579 CompleteTemporalSubscription();
580}
581
548void SubscriberConnection::HandleUnsubscribe()582void SubscriberConnection::HandleUnsubscribe()
549{583{
550 SetIsSubscribed(false);584 SetIsSubscribed(false);
585
586 if (GetIsTemporalSubscription())
587 CompleteTemporalSubscription();
551}588}
552 589
553void SubscriberConnection::HandleMetadataRefresh(uint8_t* data, uint32_t length)590void SubscriberConnection::HandleMetadataRefresh(uint8_t* data, uint32_t length)
@@ -559,7 +596,7 @@ void SubscriberConnection::HandleMetadataRefresh(uint8_t* data, uint32_t length) · 5 unmodified lines
559 m_parent->DispatchStatusMessage("Received meta-data refresh request from " + GetConnectionID() + ", preparing response...");596 m_parent->DispatchStatusMessage("Received meta-data refresh request from " + GetConnectionID() + ", preparing response...");
560 597
561 StringMap<ExpressionTreePtr> filterExpressions;598 StringMap<ExpressionTreePtr> filterExpressions;
562 const DateTime startTime = UtcNow(); //-V821599 const datetime_t startTime = UtcNow(); //-V821
563 600
564 try601 try
565 {602 {
@@ -622,8 +659,22 @@ void SubscriberConnection::HandleRotateCipherKeys() · 56 unmodified lines
622{659{
623}660}
624 661
625void SubscriberConnection::HandleUpdateProcessingInterval(uint8_t* data, uint32_t length)662void SubscriberConnection::HandleUpdateProcessingInterval(const uint8_t* data, uint32_t length)
626{663{
664 // Make sure there is enough buffer for new processing interval value
665 if (length >= 4)
666 {
667 // Next 4 bytes are an integer representing the new processing interval
668 const int32_t processingInterval = EndianConverter::Default.ConvertBigEndian(*reinterpret_cast<const int32_t*>(data));
669 SetProcessingInterval(processingInterval);
670 SendResponse(ServerResponse::Succeeded, ServerCommand::UpdateProcessingInterval, "New processing interval of " + ToString(processingInterval) + " assigned.");
671 }
672 else
673 {
674 const string message = "Not enough buffer was provided to update client processing interval.";
675 SendResponse(ServerResponse::Failed, ServerCommand::UpdateProcessingInterval, message);
676 m_parent->DispatchErrorMessage(message);
677 }
627}678}
628 679
629void SubscriberConnection::HandleDefineOperationalModes(uint8_t* data, uint32_t length)680void SubscriberConnection::HandleDefineOperationalModes(uint8_t* data, uint32_t length)
@@ -1056,6 +1107,11 @@ void SubscriberConnection::WriteHandler(const ErrorCode& error, uint32_t bytesTr · 426 unmodified lines
1056 }1107 }
1057}1108}
1058 1109
1110bool SubscriberConnection::SendResponse(uint8_t responseCode, uint8_t commandCode)
1111{
1112 return SendResponse(responseCode, commandCode, vector<uint8_t>(0));
1113}
1114
1059bool SubscriberConnection::SendResponse(uint8_t responseCode, uint8_t commandCode, const string& message)1115bool SubscriberConnection::SendResponse(uint8_t responseCode, uint8_t commandCode, const string& message)
1060{1116{
1061 return SendResponse(responseCode, commandCode, EncodeString(message));1117 return SendResponse(responseCode, commandCode, EncodeString(message));
Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberConnection.h+48−5
@@ -37,6 +37,9 @@ namespace Transport · 36 unmodified lines
37 class DataPublisher;37 class DataPublisher;
38 typedef GSF::SharedPtr<DataPublisher> DataPublisherPtr;38 typedef GSF::SharedPtr<DataPublisher> DataPublisherPtr;
39 39
40 class SubscriberConnection;
41 typedef GSF::SharedPtr<SubscriberConnection> SubscriberConnectionPtr;
42
40 // Represents a subscriber connection to a data publisher43 // Represents a subscriber connection to a data publisher
41 class SubscriberConnection : public GSF::EnableSharedThisPtr<SubscriberConnection> // NOLINT44 class SubscriberConnection : public GSF::EnableSharedThisPtr<SubscriberConnection> // NOLINT
42 {45 {
@@ -49,6 +52,9 @@ namespace Transport · 6 unmodified lines
49 std::string m_subscriptionInfo;52 std::string m_subscriptionInfo;
50 uint32_t m_operationalModes;53 uint32_t m_operationalModes;
51 uint32_t m_encoding;54 uint32_t m_encoding;
55 GSF::datetime_t m_startTimeConstraint;
56 GSF::datetime_t m_stopTimeConstraint;
57 int32_t m_processingInterval;
52 bool m_usePayloadCompression;58 bool m_usePayloadCompression;
53 bool m_useCompactMeasurementFormat;59 bool m_useCompactMeasurementFormat;
54 bool m_includeTime;60 bool m_includeTime;
@@ -79,17 +85,18 @@ namespace Transport · 24 unmodified lines
79 SignalIndexCachePtr m_signalIndexCache;85 SignalIndexCachePtr m_signalIndexCache;
80 int32_t m_timeIndex;86 int32_t m_timeIndex;
81 int64_t m_baseTimeOffsets[2];87 int64_t m_baseTimeOffsets[2];
82 DateTime m_lastPublishTime;88 datetime_t m_lastPublishTime;
83 //TSSCMeasurementParser m_tsscMeasurementParser;89 //TSSCMeasurementParser m_tsscMeasurementParser;
84 //bool m_tsscResetRequested;90 //bool m_tsscResetRequested;
85 //uint16_t m_tsscSequenceNumber;91 //uint16_t m_tsscSequenceNumber;
86 92
87 // Server request handlers93 // Server request handlers
88 void HandleSubscribe(uint8_t* data, uint32_t length);94 void HandleSubscribe(uint8_t* data, uint32_t length);
95 void HandleSubscribeFailure(const std::string& message);
89 void HandleUnsubscribe();96 void HandleUnsubscribe();
90 void HandleMetadataRefresh(uint8_t* data, uint32_t length);97 void HandleMetadataRefresh(uint8_t* data, uint32_t length);
91 void HandleRotateCipherKeys();98 void HandleRotateCipherKeys();
92 void HandleUpdateProcessingInterval(uint8_t* data, uint32_t length);99 void HandleUpdateProcessingInterval(const uint8_t* data, uint32_t length);
93 void HandleDefineOperationalModes(uint8_t* data, uint32_t length);100 void HandleDefineOperationalModes(uint8_t* data, uint32_t length);
94 void HandleConfirmNotification(uint8_t* data, uint32_t length);101 void HandleConfirmNotification(uint8_t* data, uint32_t length);
95 void HandleConfirmBufferBlock(uint8_t* data, uint32_t length);102 void HandleConfirmBufferBlock(uint8_t* data, uint32_t length);
@@ -112,43 +119,78 @@ namespace Transport · 16 unmodified lines
112 ~SubscriberConnection();119 ~SubscriberConnection();
113 120
114 const DataPublisherPtr& GetParent() const;121 const DataPublisherPtr& GetParent() const;
122 SubscriberConnectionPtr GetReference();
115 123
116 GSF::TcpSocket& CommandChannelSocket();124 GSF::TcpSocket& CommandChannelSocket();
117 125
118 // Gets or sets subscriber identification used when subscriber is known and pre-established126 // Gets or sets subscriber UUID used when subscriber is known and pre-established
119 const GSF::Guid& GetSubscriberID() const;127 const GSF::Guid& GetSubscriberID() const;
120 void SetSubscriberID(const GSF::Guid& id);128 void SetSubscriberID(const GSF::Guid& id);
121 129
130 // Gets subscriber connection identification, e.g., remote IP/port, for display and logging references
122 const std::string& GetConnectionID() const;131 const std::string& GetConnectionID() const;
132
133 // Gets subscriber remote IP address
123 const GSF::IPAddress& GetIPAddress() const;134 const GSF::IPAddress& GetIPAddress() const;
135
136 // Gets subscriber communications port
124 const std::string& GetHostName() const;137 const std::string& GetHostName() const;
125 138
139 // Gets or sets established subscriber operational modes
126 uint32_t GetOperationalModes() const;140 uint32_t GetOperationalModes() const;
127 void SetOperationalModes(uint32_t value);141 void SetOperationalModes(uint32_t value);
128 142
143 // Gets established subscriber string encoding
129 uint32_t GetEncoding() const;144 uint32_t GetEncoding() const;
130 145
146 // Gets flags that determines if this subscription is temporal based
147 bool GetIsTemporalSubscription() const;
148
149 // Gets or sets the start time temporal processing constraint
150 const GSF::datetime_t& GetStartTimeConstraint() const;
151 void SetStartTimeConstraint(const GSF::datetime_t& value);
152
153 // Gets or sets the stop time temporal processing constraint
154 const GSF::datetime_t& GetStopTimeConstraint() const;
155 void SetStopTimeConstraint(const GSF::datetime_t& value);
156
157 // Gets or sets the desired temporal processing interval, in milliseconds
158 // With the exception of the values of -1 and 0, this value specifies the desired processing interval for data, i.e.,
159 // basically a delay, or timer interval, over which to process data. A value of -1 means to use the default processing
160 // interval while a value of 0 means to process data as fast as possible.
161 int32_t GetProcessingInterval() const;
162 void SetProcessingInterval(int32_t value);
163
164 // Gets or sets flag that determines if payload compression should be enabled in data packets
131 bool GetUsePayloadCompression() const;165 bool GetUsePayloadCompression() const;
132 void SetUsePayloadCompression(bool value);166 void SetUsePayloadCompression(bool value);
133 167
168 // Gets or sets flag that determines if the compact measurement format should be used in data packets
134 bool GetUseCompactMeasurementFormat() const;169 bool GetUseCompactMeasurementFormat() const;
135 void SetUseCompactMeasurementFormat(bool value);170 void SetUseCompactMeasurementFormat(bool value);
136 171
172 // Gets or sets flag that determines if time should be included in data packets when the compact measurement format used
137 bool GetIncludeTime() const;173 bool GetIncludeTime() const;
138 void SetIncludeTime(bool value);174 void SetIncludeTime(bool value);
139 175
176 // Gets or sets flag that determines if time should be restricted to millisecond resolution in data packets when the
177 // compact measurement format used; otherwise, full resolution time will be used
140 bool GetUseMillisecondResolution() const;178 bool GetUseMillisecondResolution() const;
141 void SetUseMillisecondResolution(bool value);179 void SetUseMillisecondResolution(bool value);
142 180
181 // Gets or sets flag that determines if NaN values should be excluded from data packets
143 bool GetIsNaNFiltered() const;182 bool GetIsNaNFiltered() const;
144 void SetIsNaNFiltered(bool value);183 void SetIsNaNFiltered(bool value);
145 184
185 // Gets or sets flag that determines if subscriber connection is currently subscribed
146 bool GetIsSubscribed() const;186 bool GetIsSubscribed() const;
147 void SetIsSubscribed(bool value);187 void SetIsSubscribed(bool value);
148 188
189 // Gets or sets subscription details about subscriber
149 const std::string& GetSubscriptionInfo() const;190 const std::string& GetSubscriptionInfo() const;
150 void SetSubscriptionInfo(const std::string& value);191 void SetSubscriptionInfo(const std::string& value);
151 192
193 // Gets or sets signal index cache for subscriber representing run-time mappings for subscribed points
152 const SignalIndexCachePtr& GetSignalIndexCache() const;194 const SignalIndexCachePtr& GetSignalIndexCache() const;
153 void SetSignalIndexCache(SignalIndexCachePtr signalIndexCache);195 void SetSignalIndexCache(SignalIndexCachePtr signalIndexCache);
154 196
@@ -164,15 +206,16 @@ namespace Transport · 9 unmodified lines
164 void Start();206 void Start();
165 void Stop();207 void Stop();
166 208
167 void PublishMeasurements(const std::vector<Measurement>& measurements);
168 void PublishMeasurements(const std::vector<MeasurementPtr>& measurements);209 void PublishMeasurements(const std::vector<MeasurementPtr>& measurements);
210 void CompleteTemporalSubscription();
169 211
170 void CommandChannelSendAsync(uint8_t* data, uint32_t offset, uint32_t length);212 void CommandChannelSendAsync(uint8_t* data, uint32_t offset, uint32_t length);
171 void DataChannelSendAsync(uint8_t* data, uint32_t offset, uint32_t length);213 void DataChannelSendAsync(uint8_t* data, uint32_t offset, uint32_t length);
172 void WriteHandler(const ErrorCode& error, uint32_t bytesTransferred);214 void WriteHandler(const ErrorCode& error, uint32_t bytesTransferred);
173 215
216 bool SendResponse(uint8_t responseCode, uint8_t commandCode);
174 bool SendResponse(uint8_t responseCode, uint8_t commandCode, const std::string& message);217 bool SendResponse(uint8_t responseCode, uint8_t commandCode, const std::string& message);
175 bool SendResponse(uint8_t responseCode, uint8_t commandCode, const std::vector<uint8_t>& data = {});218 bool SendResponse(uint8_t responseCode, uint8_t commandCode, const std::vector<uint8_t>& data);
176 219
177 std::string DecodeString(const uint8_t* data, uint32_t offset, uint32_t length) const;220 std::string DecodeString(const uint8_t* data, uint32_t offset, uint32_t length) const;
178 std::vector<uint8_t> EncodeString(const std::string& value) const;221 std::vector<uint8_t> EncodeString(const std::string& value) const;
Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberInstance.cpp+4−4
@@ -562,7 +562,7 @@ void SubscriberInstance::DataStartTime(time_t unixSOC, uint16_t milliseconds) · 561 unmodified lines
562{562{
563}563}
564 564
565void SubscriberInstance::DataStartTime(DateTime startTime)565void SubscriberInstance::DataStartTime(datetime_t startTime)
566{566{
567}567}
568 568
@@ -876,7 +876,7 @@ void SubscriberInstance::ConstructConfigurationFrames(const StringMap<DeviceMeta · 307 unmodified lines
876 phasorReference->Phasor->Type = "?";876 phasorReference->Phasor->Type = "?";
877 phasorReference->Phasor->Phase = "+";877 phasorReference->Phasor->Phase = "+";
878 phasorReference->Phasor->SourceIndex = i;878 phasorReference->Phasor->SourceIndex = i;
879 phasorReference->Phasor->UpdatedOn = DateTime();879 phasorReference->Phasor->UpdatedOn = datetime_t();
880 880
881 phasorReference->Angle = nullptr;881 phasorReference->Angle = nullptr;
882 phasorReference->Magnitude = nullptr;882 phasorReference->Magnitude = nullptr;
@@ -912,7 +912,7 @@ void SubscriberInstance::ConstructConfigurationFrames(const StringMap<DeviceMeta · 29 unmodified lines
912 measurement->Reference.Kind = SignalKind::Analog;912 measurement->Reference.Kind = SignalKind::Analog;
913 measurement->PhasorSourceIndex = 0U;913 measurement->PhasorSourceIndex = 0U;
914 measurement->Description = "";914 measurement->Description = "";
915 measurement->UpdatedOn = DateTime();915 measurement->UpdatedOn = datetime_t();
916 916
917 configurationFrame->Analogs.push_back(measurement);917 configurationFrame->Analogs.push_back(measurement);
918 }918 }
@@ -946,7 +946,7 @@ void SubscriberInstance::ConstructConfigurationFrames(const StringMap<DeviceMeta · 27 unmodified lines
946 measurement->Reference.Kind = SignalKind::Digital;946 measurement->Reference.Kind = SignalKind::Digital;
947 measurement->PhasorSourceIndex = 0U;947 measurement->PhasorSourceIndex = 0U;
948 measurement->Description = "";948 measurement->Description = "";
949 measurement->UpdatedOn = DateTime();949 measurement->UpdatedOn = datetime_t();
950 950
951 configurationFrame->Digitals.push_back(measurement);951 configurationFrame->Digitals.push_back(measurement);
952 }952 }
Source/Libraries/TimeSeriesPlatformLibrary/Transport/SubscriberInstance.h+1−1
@@ -79,7 +79,7 @@ namespace Transport · 78 unmodified lines
79 virtual void StatusMessage(const std::string& message); // Defaults output to cout79 virtual void StatusMessage(const std::string& message); // Defaults output to cout
80 virtual void ErrorMessage(const std::string& message); // Defaults output to cerr80 virtual void ErrorMessage(const std::string& message); // Defaults output to cerr
81 virtual void DataStartTime(time_t unixSOC, uint16_t milliseconds);81 virtual void DataStartTime(time_t unixSOC, uint16_t milliseconds);
82 virtual void DataStartTime(DateTime startTime);82 virtual void DataStartTime(datetime_t startTime);
83 virtual void ReceivedMetadata(const std::vector<uint8_t>& payload);83 virtual void ReceivedMetadata(const std::vector<uint8_t>& payload);
84 virtual void ParsedMetadata();84 virtual void ParsedMetadata();
85 virtual void ReceivedNewMeasurements(const std::vector<MeasurementPtr>& measurements);85 virtual void ReceivedNewMeasurements(const std::vector<MeasurementPtr>& measurements);
Source/Libraries/TimeSeriesPlatformLibrary/Transport/TransportTypes.cpp+18−1
@@ -64,7 +64,7 @@ float64_t Measurement::AdjustedValue() const · 63 unmodified lines
64 return Value * Multiplier + Adder;64 return Value * Multiplier + Adder;
65}65}
66 66
67DateTime Measurement::GetDateTime() const67datetime_t Measurement::GetDateTime() const
68{68{
69 return FromTicks(Timestamp);69 return FromTicks(Timestamp);
70}70}
@@ -74,6 +74,23 @@ void Measurement::GetUnixTime(time_t& unixSOC, uint16_t& milliseconds) const · 3 unmodified lines
74 ToUnixTime(Timestamp, unixSOC, milliseconds);74 ToUnixTime(Timestamp, unixSOC, milliseconds);
75}75}
76 76
77MeasurementPtr TimeSeries::ToPtr(const Measurement& source)
78{
79 MeasurementPtr destination = NewSharedPtr<Measurement>();
80
81 destination->ID = source.ID;
82 destination->Source = source.Source;
83 destination->SignalID = source.SignalID;
84 destination->Tag = source.Tag;
85 destination->Value = source.Value;
86 destination->Adder = source.Adder;
87 destination->Multiplier = source.Multiplier;
88 destination->Timestamp = source.Timestamp;
89 destination->Flags = source.Flags;
90
91 return destination;
92}
93
77SignalReference::SignalReference() :94SignalReference::SignalReference() :
78 SignalID(Empty::Guid),95 SignalID(Empty::Guid),
79 Index(0),96 Index(0),
Source/Libraries/TimeSeriesPlatformLibrary/Transport/TransportTypes.h+5−4
@@ -97,13 +97,14 @@ namespace TimeSeries · 96 unmodified lines
97 float64_t AdjustedValue() const;97 float64_t AdjustedValue() const;
98 98
99 // Gets Timestamp as DateTime99 // Gets Timestamp as DateTime
100 DateTime GetDateTime() const;100 datetime_t GetDateTime() const;
101 101
102 // Gets Timestamp in Unix second of century and milliseconds102 // Gets Timestamp in Unix second of century and milliseconds
103 void GetUnixTime(time_t& unixSOC, uint16_t& milliseconds) const;103 void GetUnixTime(time_t& unixSOC, uint16_t& milliseconds) const;
104 };104 };
105 105
106 typedef SharedPtr<Measurement> MeasurementPtr;106 typedef SharedPtr<Measurement> MeasurementPtr;
107 MeasurementPtr ToPtr(const Measurement& source);
107 108
108 enum SignalKind : int16_t109 enum SignalKind : int16_t
109 {110 {
@@ -162,7 +163,7 @@ namespace TimeSeries · 52 unmodified lines
162 SignalReference Reference; // Parsed signal reference structure163 SignalReference Reference; // Parsed signal reference structure
163 uint16_t PhasorSourceIndex; // Measurement phasor index, if measurement represents a "Phasor"164 uint16_t PhasorSourceIndex; // Measurement phasor index, if measurement represents a "Phasor"
164 std::string Description; // Detailed measurement description (free-form)165 std::string Description; // Detailed measurement description (free-form)
165 DateTime UpdatedOn; // Time of last meta-data update166 datetime_t UpdatedOn; // Time of last meta-data update
166 };167 };
167 168
168 typedef SharedPtr<MeasurementMetadata> MeasurementMetadataPtr;169 typedef SharedPtr<MeasurementMetadata> MeasurementMetadataPtr;
@@ -174,7 +175,7 @@ namespace TimeSeries · 5 unmodified lines
174 std::string Type; // Phasor type, i.e., "V" for voltage or "I" for current175 std::string Type; // Phasor type, i.e., "V" for voltage or "I" for current
175 std::string Phase; // Phasor phase, one of, "+", "-", "0", "A", "B" or "C"176 std::string Phase; // Phasor phase, one of, "+", "-", "0", "A", "B" or "C"
176 uint16_t SourceIndex; // Phasor ordered index, uses 1-based indexing (key to MeasurementMetadata.PhasorSourceIndex)177 uint16_t SourceIndex; // Phasor ordered index, uses 1-based indexing (key to MeasurementMetadata.PhasorSourceIndex)
177 DateTime UpdatedOn; // Time of last meta-data update178 datetime_t UpdatedOn; // Time of last meta-data update
178 };179 };
179 180
180 typedef SharedPtr<PhasorMetadata> PhasorMetadataPtr;181 typedef SharedPtr<PhasorMetadata> PhasorMetadataPtr;
@@ -202,7 +203,7 @@ namespace TimeSeries · 21 unmodified lines
202 std::string VendorDeviceName; // Original vendor device name, e.g., PMU brand (if useful / provided)203 std::string VendorDeviceName; // Original vendor device name, e.g., PMU brand (if useful / provided)
203 float64_t Longitude; // Device longitude (if reported)204 float64_t Longitude; // Device longitude (if reported)
204 float64_t Latitude; // Device latitude (if reported)205 float64_t Latitude; // Device latitude (if reported)
205 DateTime UpdatedOn; // Time of last meta-data update206 datetime_t UpdatedOn; // Time of last meta-data update
206 207
207 // Associated measurement and phasor meta-data208 // Associated measurement and phasor meta-data
208 std::vector<MeasurementMetadataPtr> Measurements; // DataPublisher does not need to assign209 std::vector<MeasurementMetadataPtr> Measurements; // DataPublisher does not need to assign

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t