/// <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})"); } }
/// <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})"); } }
/// <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); }
/// <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})"); } }
/// <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); }
/// <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; }
/// <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); }
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); }
/// <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); }
/// <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; }
/// <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; }
/// <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) { }