コード例 #1
0
ファイル: Probe.cs プロジェクト: sheenvempeny/sensus
        /// <summary>
        /// Stores a <see cref="Datum"/> within the <see cref="LocalDataStore"/>. Will not throw an <see cref="Exception"/>.
        /// </summary>
        /// <returns>The datum async.</returns>
        /// <param name="datum">Datum.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public virtual Task <bool> StoreDatumAsync(Datum datum, CancellationToken?cancellationToken)
        {
            // track the most recent datum regardless of whether the datum is null or whether we're storing data
            Datum previousDatum = _mostRecentDatum;

            _mostRecentDatum          = datum;
            _mostRecentStoreTimestamp = DateTimeOffset.UtcNow;

            // fire events to notify observers of the stored data and associated UI values
            MostRecentDatumChanged?.Invoke(this, new Tuple <Datum, Datum>(previousDatum, _mostRecentDatum));
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SubCaption)));

            // datum is allowed to be null, indicating the the probe attempted to obtain data but it didn't find any (in the case of polling probes).
            if (datum != null)
            {
                datum.ProtocolId = Protocol.Id;

                if (_storeData)
                {
                    ChartDataPoint chartDataPoint = null;

                    try
                    {
                        chartDataPoint = GetChartDataPointFromDatum(datum);
                    }
                    catch (NotImplementedException)
                    {
                    }

                    if (chartDataPoint != null)
                    {
                        lock (_chartData)
                        {
                            _chartData.Add(chartDataPoint);

                            while (_chartData.Count > 0 && _chartData.Count > _maxChartDataCount)
                            {
                                _chartData.RemoveAt(0);
                            }
                        }
                    }

                    // catch any exceptions, as the caller (e.g., a probe listening) could very well be unprotected on the UI thread. throwing
                    // an exception here can crash the app.
                    try
                    {
                        return(_protocol.LocalDataStore.WriteDatumAsync(datum, cancellationToken.GetValueOrDefault()));
                    }
                    catch (Exception ex)
                    {
                        SensusServiceHelper.Get().Logger.Log("Failed to write datum:  " + ex, LoggingLevel.Normal, GetType());
                    }
                }
            }

            return(Task.FromResult(false));
        }
コード例 #2
0
ファイル: Probe.cs プロジェクト: jirlong/sensus
        /// <summary>
        /// Stores a <see cref="Datum"/> within the <see cref="LocalDataStore"/>. Will not throw an <see cref="Exception"/>.
        /// </summary>
        /// <param name="datum">Datum.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public void StoreDatum(Datum datum, CancellationToken?cancellationToken = null)
        {
            // track/limit the raw rate
            if (_rawRateCalculator.Add(datum) == DataRateCalculator.SamplingAction.Drop)
            {
                return;
            }

            // track the storage rate
            _storageRateCalculator.Add(datum);

            // set properties that we were unable to set within the datum constructor. datum is allowed to
            // be null, indicating the the probe attempted to obtain data but it didn't find any (in the
            // case of polling probes).
            if (datum != null)
            {
                datum.ProtocolId    = Protocol.Id;
                datum.ParticipantId = Protocol.ParticipantId;
            }

            // track the most recent datum regardless of whether the datum is null or whether we're storing data
            Datum previousDatum = _mostRecentDatum;

            _mostRecentDatum          = datum;
            _mostRecentStoreTimestamp = DateTimeOffset.UtcNow;

            // fire events to notify observers of the stored data and associated UI values
            MostRecentDatumChanged?.Invoke(this, new Tuple <Datum, Datum>(previousDatum, _mostRecentDatum));

            // don't update the UI too often, as doing so at really high rates causes UI deadlocks.
            if (_uiUpdateRateCalculator.Add(datum) == DataRateCalculator.SamplingAction.Keep)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SubCaption)));
            }

            // store non-null data
            if (_storeData && datum != null)
            {
                #region update chart data
                ChartDataPoint chartDataPoint = null;

                try
                {
                    chartDataPoint = GetChartDataPointFromDatum(datum);
                }
                catch (NotImplementedException)
                {
                }

                if (chartDataPoint != null)
                {
                    lock (_chartData)
                    {
                        _chartData.Add(chartDataPoint);

                        while (_chartData.Count > 0 && _chartData.Count > _maxChartDataCount)
                        {
                            _chartData.RemoveAt(0);
                        }
                    }
                }
                #endregion

                // write datum to local data store. catch any exceptions, as the caller (e.g., a listening
                // probe) could very well be unprotected on the UI thread. throwing an exception here can crash the app.
                try
                {
                    _protocol.LocalDataStore.WriteDatum(datum, cancellationToken.GetValueOrDefault());
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Failed to write datum:  " + ex, LoggingLevel.Normal, GetType());
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Stores a <see cref="Datum"/> within the <see cref="LocalDataStore"/>. Will not throw an <see cref="Exception"/>.
        /// </summary>
        /// <param name="datum">Datum.</param>
        /// <param name="cancellationToken">Cancellation token.</param>
        public async Task StoreDatumAsync(Datum datum, CancellationToken?cancellationToken = null)
        {
            // it's possible for the current method to be called when the protocol is not running. the obvious case is when
            // the protocol is paused, but there are other race-like conditions. we try to prevent this (e.g., by forcing
            // the user to start the protocol before taking a survey saved from a previous run of the app), but there are
            // probably corner cases we haven't accounted for. at the very least, there are race conditions (e.g., taking a
            // survey when a protocol is about to stop) that could cause data to be stored without a running protocol.
            if (_protocol.State != ProtocolState.Running)
            {
                return;
            }

            // track/limit the raw rate of non-null data. all null data will pass this test, and this is
            // fine given such data are generated by polling probes when no data were retrieved. such
            // return values from polling probes are used to indicate that the poll was completed, which
            // will be reflected in the _mostRecentStoreTimestamp below.
            if (datum != null)
            {
                // impose a limit on the raw data rate
                if (_rawRateCalculator.Add(datum) == DataRateCalculator.SamplingAction.Drop)
                {
                    return;
                }

                // set properties that we were unable to set within the datum constructor.
                datum.ProtocolId    = Protocol.Id;
                datum.ParticipantId = Protocol.ParticipantId;

                // tag the data if we're in tagging mode, indicated with a non-null event id on the protocol. avoid
                // any race conditions related to starting/stopping a tagging by getting the required values and
                // then checking both for validity. we need to guarantee that any tagged datum has both an id and tags.
                string        taggedEventId   = Protocol.TaggedEventId;
                List <string> taggedEventTags = Protocol.TaggedEventTags.ToList();
                if (!string.IsNullOrWhiteSpace(taggedEventId) && taggedEventTags.Count > 0)
                {
                    datum.TaggedEventId   = taggedEventId;
                    datum.TaggedEventTags = taggedEventTags;
                }

                // if the protocol is configured with a sensing agent,
                if (Protocol.Agent != null)
                {
                    datum.SensingAgentStateDescription = Protocol.Agent.StateDescription;
                }
            }

            // store non-null data
            if (_storeData && datum != null)
            {
                #region update chart data
                ChartDataPoint chartDataPoint = null;

                try
                {
                    chartDataPoint = GetChartDataPointFromDatum(datum);
                }
                catch (NotImplementedException)
                {
                }

                if (chartDataPoint != null)
                {
                    lock (_chartData)
                    {
                        _chartData.Add(chartDataPoint);

                        while (_chartData.Count > 0 && _chartData.Count > _maxChartDataCount)
                        {
                            _chartData.RemoveAt(0);
                        }
                    }
                }
                #endregion

                // write datum to local data store. catch any exceptions, as the caller (e.g., a listening
                // probe) could very well be unprotected on the UI thread. throwing an exception here can crash the app.
                try
                {
                    _protocol.LocalDataStore.WriteDatum(datum, cancellationToken.GetValueOrDefault());

                    // track the storage rate
                    _storageRateCalculator.Add(datum);
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Failed to write datum:  " + ex, LoggingLevel.Normal, GetType());
                }
            }

            // update the timestamp of the most recent store. this is used to calculate storage latency, so we
            // do not restrict its values to those obtained when non-null data are stored (see above). some
            // probes call this method with null data to signal that they have run their collection to completion.
            _mostRecentStoreTimestamp = DateTimeOffset.UtcNow;

            // don't update the UI too often, as doing so at really high rates causes UI deadlocks. always let
            // null data update the UI, as these are only generated by polling probes at low rates.
            if (datum == null || _uiUpdateRateCalculator.Add(datum) == DataRateCalculator.SamplingAction.Keep)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SubCaption)));
            }

            // track the most recent datum regardless of whether the datum is null or whether we're storing data
            Datum previousDatum = _mostRecentDatum;
            _mostRecentDatum = datum;

            // notify observers of the stored data and associated UI values
            await(MostRecentDatumChanged?.Invoke(previousDatum, _mostRecentDatum) ?? Task.CompletedTask);

            // let the script probe's agent observe the data, as long as the probe is enabled and there is an agent.
            Protocol.TryGetProbe(typeof(ScriptProbe), out Probe scriptProbe);
            if (scriptProbe?.Enabled ?? false)
            {
                // agents might be third-party and badly behaving...catch their exceptions.
                try
                {
                    await((scriptProbe as ScriptProbe).Agent?.ObserveAsync(datum) ?? Task.CompletedTask);
                }
                catch (Exception ex)
                {
                    SensusServiceHelper.Get().Logger.Log("Exception while script probe agent was observing datum:  " + ex.Message, LoggingLevel.Normal, GetType());
                }
            }

            // let the protocol's sensing agent observe the data, and schedule any returned control
            // completion check. agents might be third-party and badly behaving...catch their exceptions.
            try
            {
                await Protocol.ScheduleAgentControlCompletionCheckAsync(await (Protocol.Agent?.ObserveAsync(datum, cancellationToken.GetValueOrDefault()) ?? Task.FromResult <ControlCompletionCheck>(null)));
            }
            catch (Exception ex)
            {
                SensusServiceHelper.Get().Logger.Log("Exception while sensing agent was observing datum:  " + ex.Message, LoggingLevel.Normal, GetType());
            }
        }