/// <summary>
        /// Establishes a connection to the given UNIX socket file
        /// </summary>
        /// <param name="initMessage">Init message to send to the server</param>
        /// <param name="socketPath">Path to the UNIX socket file</param>
        /// <param name="cancellationToken">Optional cancellation token</param>
        /// <returns>Asynchronous task</returns>
        /// <exception cref="IncompatibleVersionException">API level is incompatible</exception>
        /// <exception cref="IOException">Connection mode is unavailable</exception>
        /// <exception cref="OperationCanceledException">Operation has been cancelled</exception>
        /// <exception cref="SocketException">Connection has been closed</exception>
        protected async Task Connect(ClientInitMessage initMessage, string socketPath, CancellationToken cancellationToken)
        {
            // Create a new connection
            UnixDomainSocketEndPoint endPoint = new UnixDomainSocketEndPoint(socketPath);

            _unixSocket.Connect(endPoint);

            // Read the server init message
            ServerInitMessage ownMessage    = new ServerInitMessage();
            ServerInitMessage serverMessage = await Receive <ServerInitMessage>(cancellationToken);

            Id = serverMessage.Id;

            // Switch mode
            initMessage.Version = Defaults.ProtocolVersion;
            await Send(initMessage, cancellationToken);

            // Check the result
            BaseResponse response = await ReceiveResponse(cancellationToken);

            if (!response.Success)
            {
                ErrorResponse errorResponse = (ErrorResponse)response;
                if (errorResponse.ErrorType == nameof(IncompatibleVersionException))
                {
                    throw new IncompatibleVersionException(errorResponse.ErrorMessage);
                }
                throw new IOException($"Could not set connection type {_connectionMode} ({errorResponse.ErrorType}: {errorResponse.ErrorMessage})");
            }
        }
Example #2
0
        /// <summary>
        /// Establishes a connection to the given UNIX socket file
        /// </summary>
        /// <param name="initMessage">Init message to send to the server</param>
        /// <param name="socketPath">Path to the UNIX socket file</param>
        /// <param name="cancellationToken">Optional cancellation token</param>
        /// <returns>Asynchronous task</returns>
        /// <exception cref="IncompatibleVersionException">API level is incompatible</exception>
        /// <exception cref="IOException">Connection mode is unavailable</exception>
        protected async Task Connect(ClientInitMessage initMessage, string socketPath, CancellationToken cancellationToken)
        {
            // Create a new connection
            UnixDomainSocketEndPoint endPoint = new UnixDomainSocketEndPoint(socketPath);

            _unixSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
            _unixSocket.Connect(endPoint);

            // Make sure we can deserialize incoming data
            _networkStream = new NetworkStream(_unixSocket);
            _streamReader  = new StreamReader(_networkStream);
            InitReader();

            // Verify server init message
            ServerInitMessage expectedMessage = new ServerInitMessage();
            ServerInitMessage serverMessage   = await Receive <ServerInitMessage>(cancellationToken);

            if (serverMessage.Version < expectedMessage.Version)
            {
                throw new IncompatibleVersionException($"Incompatible API version (expected {expectedMessage.Version}, got {serverMessage.Version}");
            }
            Id = serverMessage.Id;

            // Switch mode
            await Send(initMessage);

            BaseResponse response = await ReceiveResponse <object>(cancellationToken);

            if (!response.Success)
            {
                ErrorResponse errorResponse = (ErrorResponse)response;
                throw new IOException($"Could not set connection type {_connectionMode} ({errorResponse.ErrorType}: {errorResponse.ErrorMessage})");
            }
        }
Example #3
0
        /// <summary>
        /// Constructor of the subscription processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public ModelSubscription(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            SubscribeInitMessage subscribeInitMessage = (SubscribeInitMessage)initMessage;

            _mode = subscribeInitMessage.SubscriptionMode;
            if (subscribeInitMessage.Filters != null)
            {
                _filters = Filter.ConvertFilters(subscribeInitMessage.Filters);
            }
#pragma warning disable CS0612 // Type or member is obsolete
            else if (!string.IsNullOrEmpty(subscribeInitMessage.Filter))
            {
                _filters = Filter.ConvertFilters(subscribeInitMessage.Filter);
            }
#pragma warning restore CS0612 // Type or member is obsolete
            else
            {
                _filters = Array.Empty <object[]>();
            }

            lock (_subscriptions)
            {
                _subscriptions.Add(this);
            }
            conn.Logger.Debug("Subscription processor registered in {0} mode", _mode);
        }
Example #4
0
        /// <summary>
        /// Establishes a connection to the given UNIX socket file
        /// </summary>
        /// <param name="initMessage">Init message to send to the server</param>
        /// <param name="socketPath">Path to the UNIX socket file</param>
        /// <param name="cancellationToken">Optional cancellation token</param>
        /// <returns>Asynchronous task</returns>
        /// <exception cref="IncompatibleVersionException">API level is incompatible</exception>
        /// <exception cref="IOException">Connection mode is unavailable</exception>
        /// <exception cref="OperationCanceledException">Operation has been cancelled</exception>
        /// <exception cref="SocketException">Connection has been closed</exception>
        protected async Task Connect(ClientInitMessage initMessage, string socketPath, CancellationToken cancellationToken)
        {
            // Create a new connection
            UnixDomainSocketEndPoint endPoint = new UnixDomainSocketEndPoint(socketPath);

            _unixSocket.Connect(endPoint);

            // Verify server init message
            ServerInitMessage ownMessage    = new ServerInitMessage();
            ServerInitMessage serverMessage = await Receive <ServerInitMessage>(cancellationToken);

            if (serverMessage.Version < ownMessage.Version)
            {
                throw new IncompatibleVersionException($"Incompatible API version (need {ownMessage.Version}, got {serverMessage.Version}");
            }
            Id = serverMessage.Id;

            // Switch mode
            await Send(initMessage, cancellationToken);

            BaseResponse response = await ReceiveResponse(cancellationToken);

            if (!response.Success)
            {
                ErrorResponse errorResponse = (ErrorResponse)response;
                throw new IOException($"Could not set connection type {_connectionMode} ({errorResponse.ErrorType}: {errorResponse.ErrorMessage})");
            }
        }
Example #5
0
        /// <summary>
        /// Attempt to retrieve a processor for the given connection
        /// </summary>
        /// <param name="conn">Connection to get a processor for</param>
        /// <returns>Instance of a base processor</returns>
        private static async Task <Base> GetConnectionProcessor(Connection conn)
        {
            try
            {
                JsonDocument response = await conn.ReceiveJson();

                ClientInitMessage initMessage = JsonSerializer.Deserialize <ClientInitMessage>(response.RootElement.GetRawText(), JsonHelper.DefaultJsonOptions);
                switch (initMessage.Mode)
                {
                case ConnectionMode.Command:
                    initMessage = JsonSerializer.Deserialize <CommandInitMessage>(response.RootElement.GetRawText(), JsonHelper.DefaultJsonOptions);
                    return(new Command(conn));

                case ConnectionMode.Intercept:
                    initMessage = JsonSerializer.Deserialize <InterceptInitMessage>(response.RootElement.GetRawText(), JsonHelper.DefaultJsonOptions);
                    return(new Interception(conn, initMessage));

                case ConnectionMode.Subscribe:
                    initMessage = JsonSerializer.Deserialize <SubscribeInitMessage>(response.RootElement.GetRawText(), JsonHelper.DefaultJsonOptions);
                    return(new Subscription(conn, initMessage));

                default:
                    throw new ArgumentException("Invalid connection mode");
                }
            }
            catch (Exception e)
            {
                conn.Logger.Error(e, "Failed to get connection processor");
                await conn.SendResponse(e);
            }

            return(null);
        }
        /// <summary>
        /// Constructor of the interception processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public Interception(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            InterceptInitMessage interceptInitMessage = (InterceptInitMessage)initMessage;

            _mode = interceptInitMessage.InterceptionMode;

            _interceptors.TryAdd(this, _mode);
        }
Example #7
0
        /// <summary>
        /// Constructor of the interception processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public CodeInterception(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            InterceptInitMessage interceptInitMessage = (InterceptInitMessage)initMessage;

            _mode          = interceptInitMessage.InterceptionMode;
            _channels      = (interceptInitMessage.Channels != null) ? interceptInitMessage.Channels.ToList() : new List <CodeChannel>(Enum.GetValues(typeof(CodeChannel)).Cast <CodeChannel>());
            _filters       = interceptInitMessage.Filters ?? new List <string>();
            _priorityCodes = interceptInitMessage.PriortyCodes;
        }
Example #8
0
        /// <summary>
        /// Constructor of the code stream interpreter
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message from the client</param>
        public CodeStream(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            CodeStreamInitMessage codeStreamInitMessage = (CodeStreamInitMessage)initMessage;

            _bufferSize = codeStreamInitMessage.BufferSize;
            if (_bufferSize < 1 || _bufferSize > DuetAPI.Connection.Defaults.MaxCodeBufferSize)
            {
                throw new ArgumentException("BufferSize is out of range");
            }
            _channel = codeStreamInitMessage.Channel;
            conn.Logger.Debug("CodeStream processor added");
        }
        /// <summary>
        /// Constructor of the subscription processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public Subscription(Connection conn, ClientInitMessage initMessage) : base(conn, initMessage)
        {
            lock (_subscriptions)
            {
                _subscriptions.Add(this);
            }

            _mode = (initMessage as SubscribeInitMessage).SubscriptionMode;
            using (Model.Provider.AccessReadOnly())
            {
                _model = (MachineModel)Model.Provider.Get.Clone();
            }
        }
        /// <summary>
        /// Attempt to retrieve a processor for the given connection
        /// </summary>
        /// <param name="conn">Connection to get a processor for</param>
        /// <returns>Instance of a base processor</returns>
        private static async Task <Base> GetConnectionProcessor(Connection conn)
        {
            try
            {
                string response = await conn.ReceivePlainJson();

                ClientInitMessage initMessage = JsonSerializer.Deserialize <ClientInitMessage>(response, JsonHelper.DefaultJsonOptions);

                // Check the version number
                if (initMessage.Version < MinimumProtocolVersion)
                {
                    string message = $"Incompatible protocol version (got {initMessage.Version}, need {MinimumProtocolVersion} or higher)";
                    conn.Logger.Warn(message);
                    await conn.SendResponse(new IncompatibleVersionException(message));

                    return(null);
                }
                else if (initMessage.Version != Defaults.ProtocolVersion)
                {
                    conn.Logger.Warn("Client with outdated protocol version connected (got {0}, want {1})", initMessage.Version, Defaults.ProtocolVersion);
                }

                // Check the requested mode
                switch (initMessage.Mode)
                {
                case ConnectionMode.Command:
                    initMessage = JsonSerializer.Deserialize <CommandInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new Command(conn));

                case ConnectionMode.Intercept:
                    initMessage = JsonSerializer.Deserialize <InterceptInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new Interception(conn, initMessage));

                case ConnectionMode.Subscribe:
                    initMessage = JsonSerializer.Deserialize <SubscribeInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new Subscription(conn, initMessage));

                default:
                    throw new ArgumentException("Invalid connection mode");
                }
            }
            catch (Exception e)
            {
                conn.Logger.Error(e, "Failed to get connection processor");
                await conn.SendResponse(e);
            }

            return(null);
        }
        /// <summary>
        /// Constructor of the subscription processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public Subscription(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            SubscribeInitMessage subscribeInitMessage = (SubscribeInitMessage)initMessage;

            _mode = subscribeInitMessage.SubscriptionMode;
            if (!string.IsNullOrEmpty(subscribeInitMessage.Filter))
            {
                string[] filterStrings = subscribeInitMessage.Filter.Split(',', '|', '\r', '\n', ' ');
                _filters = filterStrings.Select(filter => filter.Split('/')).ToArray();
            }

            lock (_subscriptions)
            {
                _subscriptions.Add(this);
            }
        }
        /// <summary>
        /// Constructor of the subscription processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public Subscription(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            SubscribeInitMessage subscribeInitMessage = (SubscribeInitMessage)initMessage;

            _mode = subscribeInitMessage.SubscriptionMode;
            if (!string.IsNullOrEmpty(subscribeInitMessage.Filter))
            {
                _filters = Filter.ConvertFilters(subscribeInitMessage.Filter);
            }

            lock (_subscriptions)
            {
                _subscriptions.Add(this);
            }
            conn.Logger.Debug("Subscription processor registered in {0} mode", _mode);
        }
Example #13
0
        private static async Task <Base> GetConnectionProcessor(Connection conn)
        {
            try
            {
                JObject response = await conn.ReceiveJson();

                if (response == null)
                {
                    return(null);
                }

                ClientInitMessage initMessage = response.ToObject <ClientInitMessage>();
                switch (initMessage.Mode)
                {
                case ConnectionMode.Command:
                    initMessage = response.ToObject <CommandInitMessage>();
                    return(new Command(conn, initMessage));

                case ConnectionMode.Intercept:
                    initMessage = response.ToObject <InterceptInitMessage>();
                    return(new Interception(conn, initMessage));

                case ConnectionMode.Subscribe:
                    initMessage = response.ToObject <SubscribeInitMessage>();
                    return(new Subscription(conn, initMessage));

                default:
                    throw new ArgumentException("Invalid connection mode");
                }
            }
            catch (Exception e)
            {
                await conn.SendResponse(e);
            }

            return(null);
        }
Example #14
0
        /// <summary>
        /// Attempt to retrieve a processor for the given connection
        /// </summary>
        /// <param name="conn">Connection to get a processor for</param>
        /// <returns>Instance of a base processor</returns>
        private static async Task <Base> GetConnectionProcessor(Connection conn)
        {
            try
            {
                // Read the init message from the client
                string response = await conn.ReceivePlainJson();

                ClientInitMessage initMessage = JsonSerializer.Deserialize <ClientInitMessage>(response, JsonHelper.DefaultJsonOptions);
                conn.ApiVersion = initMessage.Version;

                // Check the version number
                if (initMessage.Version < MinimumProtocolVersion || initMessage.Version > Defaults.ProtocolVersion)
                {
                    string message = $"Incompatible protocol version (got {initMessage.Version}, need {MinimumProtocolVersion} to {Defaults.ProtocolVersion})";
                    conn.Logger.Warn(message);
                    await conn.SendResponse(new IncompatibleVersionException(message));

                    return(null);
                }
                else if (initMessage.Version != Defaults.ProtocolVersion)
                {
                    conn.Logger.Warn("Client with outdated protocol version connected (got {0}, want {1})", initMessage.Version, Defaults.ProtocolVersion);
                }

                // Check the requested mode
                switch (initMessage.Mode)
                {
                case ConnectionMode.Command:
                    if (!conn.CheckCommandPermissions(Command.SupportedCommands))
                    {
                        throw new UnauthorizedAccessException("Insufficient permissions");
                    }
                    initMessage = JsonSerializer.Deserialize <CommandInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new Command(conn));

                case ConnectionMode.Intercept:
                    if (!conn.CheckCommandPermissions(CodeInterception.SupportedCommands))
                    {
                        throw new UnauthorizedAccessException("Insufficient permissions");
                    }
                    initMessage = JsonSerializer.Deserialize <InterceptInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new CodeInterception(conn, initMessage));

                case ConnectionMode.Subscribe:
                    if (!conn.CheckCommandPermissions(ModelSubscription.SupportedCommands))
                    {
                        throw new UnauthorizedAccessException("Insufficient permissions");
                    }
                    initMessage = JsonSerializer.Deserialize <SubscribeInitMessage>(response, JsonHelper.DefaultJsonOptions);
                    return(new ModelSubscription(conn, initMessage));

                default:
                    throw new ArgumentException("Invalid connection mode");
                }
            }
            catch (Exception e)
            {
                conn.Logger.Error(e, "Failed to assign connection processor");
                await conn.SendResponse(e);
            }

            return(null);
        }
 /// <summary>
 /// Constructor of the interception processor
 /// </summary>
 /// <param name="conn">Connection instance</param>
 /// <param name="initMessage">Initialization message</param>
 public Interception(Connection conn, ClientInitMessage initMessage) : base(conn, initMessage)
 {
     _interceptors.TryAdd(this, (initMessage as InterceptInitMessage).InterceptionMode);
 }
Example #16
0
        /// <summary>
        /// Constructor of the interception processor
        /// </summary>
        /// <param name="conn">Connection instance</param>
        /// <param name="initMessage">Initialization message</param>
        public Interception(Connection conn, ClientInitMessage initMessage) : base(conn)
        {
            InterceptInitMessage interceptInitMessage = (InterceptInitMessage)initMessage;

            _mode = interceptInitMessage.InterceptionMode;
        }
Example #17
0
 /// <summary>
 /// Constructor of the subscription processor
 /// </summary>
 /// <param name="conn">Connection instance</param>
 /// <param name="initMessage">Initialization message</param>
 public Subscription(Connection conn, ClientInitMessage initMessage) : base(conn, initMessage)
 {
     _mode = (initMessage as SubscribeInitMessage).SubscriptionMode;
 }
Example #18
0
 /// <summary>
 /// Base constructor for connection interpreters. Invoke this from any derived class
 /// </summary>
 /// <param name="conn">Connection instance</param>
 /// <param name="initMessage">Deserialized initialization message</param>
 public Base(Connection conn, ClientInitMessage initMessage)
 {
     Connection = conn;
 }
 /// <summary>
 /// Constructor of the command interpreter
 /// </summary>
 /// <param name="conn">Connection instance</param>
 /// <param name="initMessage">Initialization message</param>
 public Command(Connection conn, ClientInitMessage initMessage) : base(conn, initMessage)
 {
 }