Example #1
0
        /// <summary>
        /// Assigns every property from another instance
        /// </summary>
        /// <param name="from">Object to assign from</param>
        /// <exception cref="ArgumentNullException">other is null</exception>
        /// <exception cref="ArgumentException">Types do not match</exception>
        public void Assign(object from)
        {
            if (from == null)
            {
                throw new ArgumentNullException();
            }
            if (!(from is MachineModel other))
            {
                throw new ArgumentException("Invalid type");
            }

            Channels.Assign(other.Channels);
            Electronics.Assign(other.Electronics);
            ListHelpers.AssignList(Fans, other.Fans);
            Heat.Assign(other.Heat);
            Job.Assign(other.Job);
            MessageBox.Assign(other.MessageBox);
            ListHelpers.AssignList(Messages, other.Messages);
            Move.Assign(other.Move);
            Network.Assign(other.Network);
            Scanner.Assign(other.Scanner);
            Sensors.Assign(other.Sensors);
            ListHelpers.AssignList(Spindles, other.Spindles);
            State.Assign(other.State);
            ListHelpers.AssignList(Storages, other.Storages);
            ListHelpers.AssignList(Tools, other.Tools);
            ListHelpers.AssignList(UserVariables, other.UserVariables);
        }
        // TODO add Sensors here holding info about thermistors

        /// <summary>
        /// Assigns every property of another instance of this one
        /// </summary>
        /// <param name="from">Object to assign from</param>
        /// <exception cref="ArgumentNullException">other is null</exception>
        /// <exception cref="ArgumentException">Types do not match</exception>
        public void Assign(object from)
        {
            if (from == null)
            {
                throw new ArgumentNullException();
            }
            if (!(from is Sensors other))
            {
                throw new ArgumentException("Invalid type");
            }

            ListHelpers.AssignList(Endstops, other.Endstops);
            ListHelpers.AssignList(Probes, other.Probes);
        }
        /// <summary>
        /// Task that keeps pushing model updates to the client
        /// </summary>
        /// <returns>Task that represents the lifecycle of a connection</returns>
        public override async Task Process()
        {
            try
            {
                // First send over the full machine model
                JObject currentObject, lastObject, patch = null;
                lock (_model)
                {
                    currentObject = lastObject = JObject.FromObject(_model, JsonHelper.DefaultSerializer);
                    _model.Messages.Clear();
                }
                await Connection.Send(currentObject.ToString(Formatting.None) + "\n");

                do
                {
                    // Wait for an acknowledgement from the client if anything was sent before
                    if (patch == null || patch.HasValues)
                    {
                        BaseCommand command = await Connection.ReceiveCommand();

                        if (command == null)
                        {
                            return;
                        }

                        if (!SupportedCommands.Contains(command.GetType()))
                        {
                            throw new ArgumentException($"Invalid command {command.Command} (wrong mode?)");
                        }
                    }

                    // Wait for another update
                    if (_mode == SubscriptionMode.Patch)
                    {
                        lastObject = currentObject;
                    }
                    await _updateAvailableEvent.WaitAsync(Program.CancelSource.Token);

                    // Get the updated object model
                    lock (_model)
                    {
                        using (Model.Provider.AccessReadOnly())
                        {
                            // NB: This could be further improved so that all the JSON tokens are written via the INotifyPropertyChanged events
                            _model.Assign(Model.Provider.Get);
                        }
                        lock (_messages)
                        {
                            ListHelpers.AssignList(_model.Messages, _messages);
                            _messages.Clear();
                        }
                        currentObject = JObject.FromObject(_model, JsonHelper.DefaultSerializer);
                    }

                    // Provide the model update
                    if (_mode == SubscriptionMode.Full)
                    {
                        // Send the entire object model in Full mode
                        await Connection.Send(currentObject.ToString(Formatting.None) + "\n");
                    }
                    else
                    {
                        // Only create a diff in Patch mode
                        patch = JsonHelper.DiffObject(lastObject, currentObject);

                        // Compact the job layers. There is no point in sending them all every time an update occurs
                        if (patch.ContainsKey("job") && patch.Value <JObject>("job").ContainsKey("layers"))
                        {
                            JArray layersArray = patch["job"].Value <JArray>("layers");
                            while (!layersArray[0].HasValues)
                            {
                                layersArray.RemoveAt(0);
                            }
                        }

                        // Send the patch unless it is empty
                        if (patch.HasValues)
                        {
                            await Connection.Send(patch.ToString(Formatting.None) + "\n");
                        }
                    }
                } while (!Program.CancelSource.IsCancellationRequested);
            }
            finally
            {
                lock (_subscriptions)
                {
                    _subscriptions.Remove(this);
                }
            }
        }