Showing the changes to Source/Libraries/TimeSeriesPlatformLibrary/Transport (11 of 28 files). Show all
Unified · Split
| @@ -36,24 +36,13 @@ using namespace GSF::FilterExpressions; · 35 unmodified lines | |||
| 36 | using namespace GSF::TimeSeries; | 36 | using namespace GSF::TimeSeries; |
| 37 | using namespace GSF::TimeSeries::Transport; | 37 | using namespace GSF::TimeSeries::Transport; |
| 38 | 38 | ||
| 39 | struct 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 | |||
| 51 | DataPublisher::DataPublisher(const TcpEndPoint& endpoint) : | 39 | DataPublisher::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 | ||
| 114 | void DataPublisher::ConnectionTerminated(const SubscriberConnectionPtr& connection) | ||
| 115 | { | ||
| 116 | DispatchClientDisconnected(connection); | ||
| 117 | } | ||
| 118 | |||
| 125 | void DataPublisher::RemoveConnection(const SubscriberConnectionPtr& connection) | 119 | void 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 | ||
| 172 | void DataPublisher::DispatchClientConnected(const GSF::Guid& subscriberID, const string& connectionID) | 163 | void DataPublisher::DispatchClientConnected(const SubscriberConnectionPtr& connection) |
| 164 | { | ||
| 165 | SubscriberConnection* connectionReference = &*connection; | ||
| 166 | Dispatch(&ClientConnectedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**)); | ||
| 167 | } | ||
| 168 | |||
| 169 | void DataPublisher::DispatchClientDisconnected(const SubscriberConnectionPtr& connection) | ||
| 170 | { | ||
| 171 | SubscriberConnection* connectionReference = &*connection; | ||
| 172 | Dispatch(&ClientDisconnectedDispatcher, reinterpret_cast<uint8_t*>(&connectionReference), 0, sizeof(SubscriberConnection**)); | ||
| 173 | } | ||
| 174 | |||
| 175 | void 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 | ||
| 178 | void DataPublisher::DispatchClientDisconnected(const GSF::Guid& subscriberID, const std::string& connectionID) | 181 | void 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 | ||
| 208 | void DataPublisher::ClientConnectedDispatcher(DataPublisher* source, const vector<uint8_t>& buffer) | 211 | void 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 | ||
| 223 | void DataPublisher::ClientDisconnectedDispatcher(DataPublisher* source, const std::vector<uint8_t>& buffer) | 224 | void 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 | |||
| 239 | void 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 | |||
| 252 | void 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 | ||
| 238 | int32_t DataPublisher::GetColumnIndex(const GSF::Data::DataTablePtr& table, const std::string& columnName) | 265 | int32_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 | ||
| 684 | void DataPublisher::PublishMeasurements(const vector<Measurement>& measurements) | 711 | void 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 | ||
| 690 | void DataPublisher::PublishMeasurements(const vector<MeasurementPtr>& measurements) | 723 | void 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 | ||
| 696 | const GSF::Guid& DataPublisher::GetNodeID() const | 736 | const 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 | ||
| 786 | bool DataPublisher::GetSupportsTemporalSubscriptions() const | ||
| 787 | { | ||
| 788 | return m_supportsTemporalSubscriptions; | ||
| 789 | } | ||
| 790 | |||
| 791 | void DataPublisher::SetSupportsTemporalSubscriptions(bool value) | ||
| 792 | { | ||
| 793 | m_supportsTemporalSubscriptions = value; | ||
| 794 | } | ||
| 795 | |||
| 746 | uint32_t DataPublisher::GetCipherKeyRotationPeriod() const | 796 | uint32_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 | |||
| 823 | void DataPublisher::RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback) | 873 | void DataPublisher::RegisterClientDisconnectedCallback(const SubscriberConnectionCallback& clientDisconnectedCallback) |
| 824 | { | 874 | { |
| 825 | m_clientDisconnectedCallback = clientDisconnectedCallback; | 875 | m_clientDisconnectedCallback = clientDisconnectedCallback; |
| 826 | } | 876 | } |
| 877 | |||
| 878 | void DataPublisher::RegisterTemporalSubscriptionRequestedCallback(const SubscriberConnectionCallback& temporalSubscriptionRequestedCallback) | ||
| 879 | { | ||
| 880 | m_temporalSubscriptionRequestedCallback = temporalSubscriptionRequestedCallback; | ||
| 881 | } | ||
| 882 | |||
| 883 | void DataPublisher::RegisterTemporalProcessingIntervalChangeRequestedCallback(const SubscriberConnectionCallback& temporalProcessingIntervalChangeRequestedCallback) | ||
| 884 | { | ||
| 885 | m_temporalProcessingIntervalChangeRequestedCallback = temporalProcessingIntervalChangeRequestedCallback; | ||
| 886 | } | ||
| @@ -44,12 +44,13 @@ namespace Transport · 43 unmodified lines | |||
| 44 | { | 44 | { |
| 45 | class DataPublisher : public EnableSharedThisPtr<DataPublisher> // NOLINT | 45 | class DataPublisher : public EnableSharedThisPtr<DataPublisher> // NOLINT |
| 46 | { | 46 | { |
| 47 | private: | 47 | public: |
| 48 | // Function pointer types | 48 | // 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 dispatch | 54 | // Structure used to dispatch |
| 54 | // callbacks on the callback thread. | 55 | // callbacks on the callback thread. |
| 55 | struct CallbackDispatcher | 56 | 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 handlers | 95 | // 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 | // Callbacks | 101 | // 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 | // Dispatchers | 109 | // 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 tables | 135 | // 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 dataset | 138 | // 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 registration | 189 | // 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 | }; |
| @@ -134,7 +134,7 @@ namespace Transport · 133 unmodified lines | |||
| 134 | 134 | ||
| 135 | class DataSubscriber // NOLINT | 135 | class DataSubscriber // NOLINT |
| 136 | { | 136 | { |
| 137 | private: | 137 | public: |
| 138 | // Function pointer types | 138 | // 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 dispatch | 148 | // Structure used to dispatch |
| 148 | // callbacks on the callback thread. | 149 | // callbacks on the callback thread. |
| 149 | struct CallbackDispatcher | 150 | struct CallbackDispatcher |
| @@ -263,14 +264,14 @@ namespace Transport · 113 unmodified lines | |||
| 263 | // Callback registration | 264 | // 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. |
| @@ -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 | ||
| 60 | void PublisherInstance::HandleClientConnected(DataPublisher* source, const GSF::Guid& subscriberID, const std::string& connectionID) | 60 | void 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 | ||
| 66 | void PublisherInstance::HandleClientDisconnected(DataPublisher* source, const GSF::Guid& subscriberID, const std::string& connectionID) | 66 | void 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 | |||
| 72 | void PublisherInstance::HandleTemporalSubscriptionRequested(DataPublisher* source, const SubscriberConnectionPtr& connection) | ||
| 73 | { | ||
| 74 | PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData()); | ||
| 75 | instance->TemporalSubscriptionRequested(connection); | ||
| 76 | } | ||
| 77 | |||
| 78 | void PublisherInstance::HandleTemporalProcessingIntervalChangeRequested(DataPublisher* source, const SubscriberConnectionPtr& connection) | ||
| 79 | { | ||
| 80 | PublisherInstance* instance = static_cast<PublisherInstance*>(source->GetUserData()); | ||
| 81 | instance->TemporalProcessingIntervalChangeRequested(connection); | ||
| 70 | } | 82 | } |
| 71 | 83 | ||
| 72 | void PublisherInstance::StatusMessage(const string& message) | 84 | void 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 | ||
| 82 | void PublisherInstance::ClientConnected(const GSF::Guid& subscriberID, const string& connectionID) | 94 | void PublisherInstance::ClientConnected(const SubscriberConnectionPtr& connection) |
| 95 | { | ||
| 96 | cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " connected..." << endl << endl; | ||
| 97 | } | ||
| 98 | |||
| 99 | void PublisherInstance::ClientDisconnected(const SubscriberConnectionPtr& connection) | ||
| 100 | { | ||
| 101 | cout << "Client \"" << connection->GetConnectionID() << "\" with subscriber ID " << ToString(connection->GetSubscriberID()) << " disconnected..." << endl << endl; | ||
| 102 | } | ||
| 103 | |||
| 104 | void 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 | ||
| 87 | void PublisherInstance::ClientDisconnected(const GSF::Guid& subscriberID, const std::string& connectionID) | 109 | void 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 | ||
| 92 | void PublisherInstance::Initialize() | 114 | void 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 | } |
| @@ -43,14 +43,18 @@ namespace Transport · 42 unmodified lines | |||
| 43 | // Internal subscription event handlers | 43 | // 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 cout | 52 | virtual void StatusMessage(const std::string& message); // Defaults output to cout |
| 51 | virtual void ErrorMessage(const std::string& message); // Defaults output to cerr | 53 | 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); |
| @@ -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 | ||
| 86 | SubscriberConnectionPtr SubscriberConnection::GetReference() | ||
| 87 | { | ||
| 88 | return shared_from_this(); | ||
| 89 | } | ||
| 90 | |||
| 83 | TcpSocket& SubscriberConnection::CommandChannelSocket() | 91 | TcpSocket& 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 | ||
| 137 | bool SubscriberConnection::GetIsTemporalSubscription() const | ||
| 138 | { | ||
| 139 | return m_startTimeConstraint < DateTime::MaxValue; | ||
| 140 | } | ||
| 141 | |||
| 142 | const GSF::datetime_t& SubscriberConnection::GetStartTimeConstraint() const | ||
| 143 | { | ||
| 144 | return m_startTimeConstraint; | ||
| 145 | } | ||
| 146 | |||
| 147 | void SubscriberConnection::SetStartTimeConstraint(const GSF::datetime_t& value) | ||
| 148 | { | ||
| 149 | m_startTimeConstraint = value; | ||
| 150 | } | ||
| 151 | |||
| 152 | const GSF::datetime_t& SubscriberConnection::GetStopTimeConstraint() const | ||
| 153 | { | ||
| 154 | return m_stopTimeConstraint; | ||
| 155 | } | ||
| 156 | |||
| 157 | void SubscriberConnection::SetStopTimeConstraint(const GSF::datetime_t& value) | ||
| 158 | { | ||
| 159 | m_stopTimeConstraint = value; | ||
| 160 | } | ||
| 161 | |||
| 162 | int32_t SubscriberConnection::GetProcessingInterval() const | ||
| 163 | { | ||
| 164 | return m_processingInterval; | ||
| 165 | } | ||
| 166 | |||
| 167 | void 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 | |||
| 129 | bool SubscriberConnection::GetUsePayloadCompression() const | 174 | bool 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 | |||
| 319 | void 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 | ||
| 362 | void SubscriberConnection::PublishMeasurements(const vector<MeasurementPtr>& measurements) | 364 | void 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 | ||
| 407 | void SubscriberConnection::CompleteTemporalSubscription() | ||
| 408 | { | ||
| 409 | SendResponse(ServerResponse::ProcessingComplete, ServerCommand::Subscribe, ToString(m_parent->GetNodeID())); | ||
| 410 | } | ||
| 411 | |||
| 405 | void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length) | 412 | void SubscriberConnection::HandleSubscribe(uint8_t* data, uint32_t length) |
| 406 | { | 413 | { |
| 407 | try | 414 | 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 | else | 550 | 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 | else | 558 | 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 | ||
| 573 | void 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 | |||
| 548 | void SubscriberConnection::HandleUnsubscribe() | 582 | void SubscriberConnection::HandleUnsubscribe() |
| 549 | { | 583 | { |
| 550 | SetIsSubscribed(false); | 584 | SetIsSubscribed(false); |
| 585 | |||
| 586 | if (GetIsTemporalSubscription()) | ||
| 587 | CompleteTemporalSubscription(); | ||
| 551 | } | 588 | } |
| 552 | 589 | ||
| 553 | void SubscriberConnection::HandleMetadataRefresh(uint8_t* data, uint32_t length) | 590 | void 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(); //-V821 | 599 | const datetime_t startTime = UtcNow(); //-V821 |
| 563 | 600 | ||
| 564 | try | 601 | try |
| 565 | { | 602 | { |
| @@ -622,8 +659,22 @@ void SubscriberConnection::HandleRotateCipherKeys() · 56 unmodified lines | |||
| 622 | { | 659 | { |
| 623 | } | 660 | } |
| 624 | 661 | ||
| 625 | void SubscriberConnection::HandleUpdateProcessingInterval(uint8_t* data, uint32_t length) | 662 | void 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 | ||
| 629 | void SubscriberConnection::HandleDefineOperationalModes(uint8_t* data, uint32_t length) | 680 | void 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 | ||
| 1110 | bool SubscriberConnection::SendResponse(uint8_t responseCode, uint8_t commandCode) | ||
| 1111 | { | ||
| 1112 | return SendResponse(responseCode, commandCode, vector<uint8_t>(0)); | ||
| 1113 | } | ||
| 1114 | |||
| 1059 | bool SubscriberConnection::SendResponse(uint8_t responseCode, uint8_t commandCode, const string& message) | 1115 | bool 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)); |
| @@ -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 publisher | 43 | // Represents a subscriber connection to a data publisher |
| 41 | class SubscriberConnection : public GSF::EnableSharedThisPtr<SubscriberConnection> // NOLINT | 44 | 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 handlers | 93 | // 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-established | 126 | // 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; |
| @@ -562,7 +562,7 @@ void SubscriberInstance::DataStartTime(time_t unixSOC, uint16_t milliseconds) · 561 unmodified lines | |||
| 562 | { | 562 | { |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | void SubscriberInstance::DataStartTime(DateTime startTime) | 565 | void 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 | } |
| @@ -79,7 +79,7 @@ namespace Transport · 78 unmodified lines | |||
| 79 | virtual void StatusMessage(const std::string& message); // Defaults output to cout | 79 | virtual void StatusMessage(const std::string& message); // Defaults output to cout |
| 80 | virtual void ErrorMessage(const std::string& message); // Defaults output to cerr | 80 | 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); |
| @@ -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 | ||
| 67 | DateTime Measurement::GetDateTime() const | 67 | datetime_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 | ||
| 77 | MeasurementPtr 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 | |||
| 77 | SignalReference::SignalReference() : | 94 | SignalReference::SignalReference() : |
| 78 | SignalID(Empty::Guid), | 95 | SignalID(Empty::Guid), |
| 79 | Index(0), | 96 | Index(0), |
| @@ -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 DateTime | 99 | // Gets Timestamp as DateTime |
| 100 | DateTime GetDateTime() const; | 100 | datetime_t GetDateTime() const; |
| 101 | 101 | ||
| 102 | // Gets Timestamp in Unix second of century and milliseconds | 102 | // 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_t | 109 | enum SignalKind : int16_t |
| 109 | { | 110 | { |
| @@ -162,7 +163,7 @@ namespace TimeSeries · 52 unmodified lines | |||
| 162 | SignalReference Reference; // Parsed signal reference structure | 163 | 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 update | 166 | 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 current | 175 | 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 update | 178 | 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 update | 206 | datetime_t UpdatedOn; // Time of last meta-data update |
| 206 | 207 | ||
| 207 | // Associated measurement and phasor meta-data | 208 | // Associated measurement and phasor meta-data |
| 208 | std::vector<MeasurementMetadataPtr> Measurements; // DataPublisher does not need to assign | 209 | std::vector<MeasurementMetadataPtr> Measurements; // DataPublisher does not need to assign |