private void ProcessTypeBatch(List <Type> batch, out bool changeDetected)
        {
            //This method assumes it's not run in parallel
            //GSA.App.Messenger.ResetLoggedMessageCount();

#if DEBUG
            changeDetected = false;

            foreach (var t in batch)
            {
                SerialiseType(t, ref changeDetected);

                if (changeDetected) // This will skip the first read but it avoids flickering
                {
                    statusProgress.Report("Reading " + t.Name);
                }

                //Nodes are a special case because they're the main type of records that would be cached but not actually sent
                var numObjects = t.GetProperties().Any(p => p.Name.ToLower().Contains("forcesend")) ? 0 : GSA.SenderDictionaries.Sum(d => d.Count(t));
                progressEstimator.AppendCurrent(WorkPhase.Conversion, numObjects);
            }
#else
            var changeLock             = new object();
            var parallelChangeDetected = false;
            Parallel.ForEach(batch, t =>
            {
                bool changed = false;
                SerialiseType(t, ref changed);

                if (changed) // This will skip the first read but it avoids flickering
                {
                    lock (changeLock)
                    {
                        parallelChangeDetected = true;
                    }
                    statusProgress.Report("Reading " + t.Name);
                }
            }
                             );

            foreach (var t in batch)
            {
                progressEstimator.AppendCurrent(WorkPhase.Conversion, GSA.SenderDictionaries.Sum(d => d.Count(t)));
            }
            changeDetected = parallelChangeDetected;
#endif
            GSA.App.LocalMessenger.Trigger();

            lock (traversedSerialisedLock)
            {
                traversedSerialisedTypes.AddRange(batch);
            }
        }
Beispiel #2
0
    /// <summary>
    /// Trigger to update stream. Is called automatically when update-global ws message is received on stream.
    /// </summary>
    public void Trigger(object sender, EventArgs e)
    {
      if ((IsBusy) || (!IsInit)) return;

      IsBusy = true;

      var startTime = DateTime.Now;

      //GSA.App.Settings.Units = GSA.App.Proxy.GetUnits();

      lock (traversedSerialisedLock)
      {
        traversedSerialisedTypes.Clear();
      }
      lock (traversedDeserialisedLock)
      {
        traversedDeserialisedTypes.Clear();
      }

      GSA.SenderDictionaries.Clear();

      // Read objects
      statusProgress.Report("Receiving streams");

      var streamIds = StreamReceivers.Keys.ToList();

      var rxObjsByStream = new Dictionary<string, List<SpeckleObject>>();

      foreach (var streamId in StreamReceivers.Keys)
      {
        rxObjsByStream.Add(streamId, StreamReceivers[streamId].GetObjects());  //This calls UpdateGlobal(), which is the trigger for pulilng information from the server
        progressEstimator.AppendCurrent(WorkPhase.ApiCalls, 1);
      }

      progressEstimator.UpdateTotal(WorkPhase.Conversion, rxObjsByStream.Keys.Sum(k => rxObjsByStream[k].Count()));

      //This list will contain ALL speckle objects received across all streams
      var rxObjs = new List<SpeckleObject>();
      var units = GSA.GsaApp.Settings.Units;
      foreach (var streamId in StreamReceivers.Keys)
      {
        double factor = 1;
        if (StreamReceivers[streamId].Units == null)
        {
          //Let the user know if any streams have no unit information
          this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Error, "Streams with no unit information", streamId));
        }
        else
        {
          factor = (1.0).ConvertUnit(StreamReceivers[streamId].Units.ShortUnitName(), units);
        }
        foreach (var o in rxObjsByStream[streamId])
        {
          if (string.IsNullOrEmpty(o.ApplicationId))
          {
            this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Information, o.GetType().Name + ((string.IsNullOrEmpty(o.Name))
              ? " with no name nor ApplicationId (identified by hashes)" : " with no name nor ApplicationId (identified by hashes)"), o.Hash));
          }
          else
          {
            o.Properties.Add("StreamId", streamId);

            try
            {
              o.Scale(factor);
            }
            catch (Exception ex)
            {
              this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Error, "Scaling issue for objects with _ids on stream: " + streamId, o._id));
              this.loggingProgress.Report(new MessageEventArgs(MessageIntent.TechnicalLog, MessageLevel.Error, ex, "Scaling issue", "StreamId=" + streamId, "_id=" + o._id));
            }

            //Populate the cache with stream IDs - review if this is needed anymroe
            GSA.App.LocalCache.SetStream(o.ApplicationId, streamId);
            rxObjs.Add(o);
          }
        }
      }

      progressEstimator.UpdateTotal(WorkPhase.Conversion, rxObjs.Count());

      //GSA.App.Messenger.Trigger();

      TimeSpan duration = DateTime.Now - startTime;
      this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Information, "Duration of reception from Speckle and scaling: " + duration.ToString(@"hh\:mm\:ss")));
      this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Telemetry, MessageLevel.Information, "receive", "reception and scaling", "duration", duration.ToString(@"hh\:mm\:ss")));

      if (rxObjs.Count() == 0)
      {
        this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Information, "No processing needed because the stream(s) contain(s) no objects"));
        statusProgress.Report("Finished receiving");
        IsBusy = false;
        return;
      }

      startTime = DateTime.Now;
      streamIds.ForEach(s => GSA.App.LocalCache.Snapshot(s));

      ProcessRxObjects(rxObjs);

      var toBeAddedGwa = GSA.App.LocalCache.GetNewGwaSetCommands();
      toBeAddedGwa.ForEach(tba => GSA.App.Proxy.SetGwa(tba));

      var toBeDeletedGwa = GSA.App.LocalCache.GetExpiredData();

      var setDeletes = toBeDeletedGwa.Where(t => t.Item4 == GwaSetCommandType.Set).ToList();
      setDeletes.ForEach(sd => GSA.App.Proxy.DeleteGWA(sd.Item1, sd.Item2, GwaSetCommandType.Set));

      var setAtDeletes = toBeDeletedGwa.Where(t => t.Item4 == GwaSetCommandType.SetAt).OrderByDescending(t => t.Item2).ToList();
      setAtDeletes.ForEach(sad => GSA.App.Proxy.DeleteGWA(sad.Item1, sad.Item2, GwaSetCommandType.SetAt));

      GSA.App.Proxy.Sync();

      GSA.App.Proxy.UpdateCasesAndTasks();
      GSA.App.Proxy.UpdateViews();

      duration = DateTime.Now - startTime;
      this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Display, MessageLevel.Information, "Duration of conversion from Speckle: " + duration.ToString(@"hh\:mm\:ss")));
      this.loggingProgress.Report(new MessageEventArgs(MessageIntent.Telemetry, MessageLevel.Information, "receive", "conversion", "duration", duration.ToString(@"hh\:mm\:ss")));
      startTime = DateTime.Now;

      statusProgress.Report("Finished receiving");
      IsBusy = false;
    }