public static async Task InvokeCommand( ContainerExecCreateParameters parameters, IImageSettings settings) { ContainerExecCreateResponse response = await _client.Containers .ExecCreateContainerAsync( settings.ContainerId, parameters); if (!string.IsNullOrEmpty(response.ID)) { using (MultiplexedStream stream = await _client.Containers .StartAndAttachContainerExecAsync( response.ID, false)) { (string stdout, string stderr)output = await stream .ReadOutputToEndAsync(CancellationToken.None); if (!string.IsNullOrEmpty(output.stderr) && output.stderr.Contains("error")) { var error = new StringBuilder(); error.AppendLine($"Error when invoking command \"{string.Join(" ", parameters.Cmd)}\""); error.AppendLine(output.stderr); throw new ContainerException(error.ToString()); } } } }
internal static async Task StartContainerAsync( DockerClient client, string containerId, ContainerAttachParameters attachParams, bool?isTTY, ContainerStartParameters startParams, CancellationToken token) { MultiplexedStream stream = null; Task streamTask = null; try { if (attachParams != null) { stream = await client.Containers.AttachContainerAsync(containerId, isTTY.GetValueOrDefault(), attachParams, token); streamTask = stream.CopyToConsoleAsync(isTTY.GetValueOrDefault(), attachParams.Stdin.GetValueOrDefault(), token); } if (!await client.Containers.StartContainerAsync(containerId, new ContainerStartParameters())) { throw new ApplicationFailedException("The container has already started."); } if (attachParams != null) { await streamTask; } } finally { stream?.Dispose(); } }
public static async Task PipeContainerOutput(IOutputObserver outputObserver, MultiplexedStream stream, CancellationToken cancellationToken) { byte[] buffer = new byte[1024]; while (!cancellationToken.IsCancellationRequested) { var result = await stream.ReadOutputAsync(buffer, 0, buffer.Length, cancellationToken); if (result.EOF) { break; } switch (result.Target) { case MultiplexedStream.TargetStream.StandardOut: await outputObserver.StandardOutput(buffer, result.Count); break; case MultiplexedStream.TargetStream.StandardError: await outputObserver.StandardError(buffer, result.Count); break; } } }
public static async Task CopyToConsoleAsync(this MultiplexedStream stream, bool tty, bool openStdin, CancellationToken cancellationToken) { Stream stdin = Stream.Null, stdout = Stream.Null, stderr = Stream.Null; ConsoleStream conin = null, conout = null; try { // TODO: What if we are not attached to a console? If config.Tty is false, this should not be an error. conout = new ConsoleStream(ConsoleDirection.Out); stdout = Console.OpenStandardOutput(); // Don't use conout's Stream because FileStream always buffers on net46. if (tty) { conout.EnableVTMode(); } else { stderr = Console.OpenStandardError(); } Task stdinRead = null; CancellationTokenSource inputCancelToken = null; if (openStdin) { conin = new ConsoleStream(ConsoleDirection.In); stdin = conin.Stream; conin.EnableRawInputMode(); if (tty) { conin.EnableVTMode(); } inputCancelToken = new CancellationTokenSource(); stdinRead = stream.CopyFromAsync(stdin, inputCancelToken.Token).ContinueWith(x => stream.CloseWrite()); } await stream.CopyOutputToAsync(stdout, stdout, stderr, cancellationToken).ConfigureAwait(false); if (stdinRead != null) { inputCancelToken.Cancel(); try { await stdinRead.ConfigureAwait(false); } catch (TaskCanceledException) { // Ignore. } } } finally { conin?.Dispose(); conout?.Dispose(); stdin.Dispose(); stdout.Dispose(); stderr.Dispose(); } }
public async Task <ContainerOutput> ReadLineAsync(MultiplexedStream multiplexedStream, CancellationToken cancellationToken) { List <byte> receiverStdOut = new List <byte>(); List <byte> receiverStdErr = new List <byte>(); byte[] buffer = new byte[15]; while (!cancellationToken.IsCancellationRequested) { var readResult = await multiplexedStream.ReadOutputAsync(buffer, 0, buffer.Length, cancellationToken); if (readResult.Target == MultiplexedStream.TargetStream.StandardError) { receiverStdErr.AddRange(buffer.Take(readResult.Count)); } if (readResult.Target != MultiplexedStream.TargetStream.StandardOut) { continue; } int newLineIndex = -1; for (int i = 0; i < readResult.Count; ++i) { if (buffer[i] == NewLineChar) { newLineIndex = i; break; } } if (newLineIndex != -1) { receiverStdOut.AddRange(buffer.Take(newLineIndex)); break; } receiverStdOut.AddRange(buffer.Take(readResult.Count)); } var result = new ContainerOutput(); try { result.StdErr = Encoding.ASCII.GetString(receiverStdErr.ToArray()); } catch (Exception ex) { this.logger.LogWarning(ex, "Ошибка при чтении stderr"); } result.StdOut = Encoding.ASCII.GetString(receiverStdOut.ToArray()); return(result); }
public async Task WriteCommandAsync(MultiplexedStream stream, StdinCommand command, CancellationToken cancellationToken) { var memoryStream = new MemoryStream(); Serializer.SerializeWithLengthPrefix(memoryStream, command, PrefixStyle.Base128); memoryStream.Seek(0, SeekOrigin.Begin); await stream.CopyFromAsync(memoryStream, cancellationToken); //await stream.WriteAsync(new byte[1024], 0, 1024, cancellationToken); }
/// <summary> /// Read and return container logs as a tuple of (stdout, stderr). /// </summary> /// <param name="id">Container ID.</param> /// <param name="tty">Was the container started with TTY enabled?</param> /// <param name="cancelToken">Cancellation token.</param> private async Task <(string, string)> GetContainerLogsAsync(string id, bool tty, CancellationToken cancelToken) { ContainerLogsParameters logParameters = new ContainerLogsParameters() { ShowStdout = true, ShowStderr = true, Follow = false }; using (MultiplexedStream logStream = await client.Containers.GetContainerLogsAsync(id, tty, logParameters, cancelToken)) return(await logStream.ReadOutputToEndAsync(cancelToken)); }
public async Task <string> ReadLineAsync(MultiplexedStream multiplexedStream, CancellationToken cancellationToken) { List <byte> received = new List <byte>(); byte[] buffer = new byte[15]; while (!cancellationToken.IsCancellationRequested) { var readResult = await multiplexedStream.ReadOutputAsync(buffer, 0, buffer.Length, cancellationToken); if (readResult.Target != MultiplexedStream.TargetStream.StandardOut) { continue; } int newLineIndex = -1; for (int i = 0; i < readResult.Count; ++i) { if (buffer[i] == NewLineChar) { newLineIndex = i; break; } } if (newLineIndex != -1) { received.AddRange(buffer.Take(newLineIndex)); break; } received.AddRange(buffer.Take(readResult.Count)); } return(Encoding.UTF8.GetString(received.ToArray())); }
protected override async Task PostProcess(String pathChanged, MultiplexedStream stream) { MemoryStream output = new MemoryStream(); await stream.CopyOutputToAsync(null, output, null, default(CancellationToken)); output.Position = 0; using (StreamReader reader = new StreamReader(output)) { String text = await reader.ReadToEndAsync(); if (text.Contains($"exec: \\\"{m_Shell}\\\": executable file not found in $PATH")) { m_Notifier.LogMessage($"Cannot execute {m_Shell} for this container ({m_Notifier.m_Container}) changing for {m_ReplacingShell}"); m_Shell = m_ReplacingShell; m_HandleError = false; await Notify(pathChanged); } else { m_Notifier.LogMessage($"Can execute {m_Shell} for this container ({m_Notifier.m_Container}) disactivating error handling"); m_HandleError = false; } } }
public RconStream(MultiplexedStream stream) => (Stream) = (stream);
public async Task <ExecutionOutputResult> ReadOutputAsync( MultiplexedStream stream, byte[] outputBuffer, ReadOnlyMemory <byte> outputStartMarker, ReadOnlyMemory <byte> outputEndMarker, CancellationToken cancellationToken ) { var currentIndex = 0; var outputStartIndex = -1; var outputEndIndex = -1; var nextStartMarkerIndexToCompare = 0; var nextEndMarkerIndexToCompare = 0; var cancelled = false; while (outputEndIndex < 0) { var(read, readCancelled) = await ReadWithCancellationAsync(stream, outputBuffer, currentIndex, outputBuffer.Length - currentIndex, cancellationToken); if (readCancelled) { cancelled = true; break; } if (read.EOF) { await Task.Delay(10, cancellationToken); continue; } if (outputStartIndex == -1) { var startMarkerEndIndex = GetMarkerEndIndex( outputBuffer, currentIndex, read.Count, outputStartMarker, ref nextStartMarkerIndexToCompare ); if (startMarkerEndIndex != -1) { outputStartIndex = startMarkerEndIndex; } } // cannot be else if -- it might have changed inside previous if if (outputStartIndex != -1) { var endMarkerEndIndex = GetMarkerEndIndex( outputBuffer, currentIndex, read.Count, outputEndMarker, ref nextEndMarkerIndexToCompare ); if (endMarkerEndIndex != -1) { outputEndIndex = endMarkerEndIndex - outputEndMarker.Length; } } currentIndex += read.Count; if (currentIndex >= outputBuffer.Length) { break; } } if (outputStartIndex < 0) { return(new(outputBuffer.AsMemory(0, currentIndex), StartOfOutputNotFound)); } if (cancelled) { return(new(outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex), ExecutionTimedOut)); } if (outputEndIndex < 0) { return(new(outputBuffer.AsMemory(outputStartIndex, currentIndex - outputStartIndex), UnexpectedEndOfOutput)); } return(new(outputBuffer.AsMemory(outputStartIndex, outputEndIndex - outputStartIndex))); }
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously protected virtual async Task PostProcess(String pathChanged, MultiplexedStream stream) { }
// Underlying stream does not handle cancellation correctly by default, see // https://stackoverflow.com/questions/12421989/networkstream-readasync-with-a-cancellation-token-never-cancels private async Task <(ReadResult result, bool cancelled)> ReadWithCancellationAsync(MultiplexedStream stream, byte[] buffer, int index, int count, CancellationToken cancellationToken) { var cancellationTaskSource = new TaskCompletionSource <object?>(); using var _ = cancellationToken.Register(() => cancellationTaskSource.SetResult(null)); var result = await Task.WhenAny( stream.ReadOutputAsync(buffer, index, count, cancellationToken), cancellationTaskSource.Task ); if (result == cancellationTaskSource.Task) { return(default, true);
/// <summary> /// Creates a new container and lists it to output. /// </summary> protected override async Task ProcessRecordAsync() { foreach (var id in ParameterResolvers.GetImageIds(Image, Id)) { var createResult = await ContainerOperations.CreateContainer( id, this.MemberwiseClone() as CreateContainerCmdlet, DkrClient); if (createResult.Warnings != null) { foreach (var w in createResult.Warnings) { if (!String.IsNullOrEmpty(w)) { WriteWarning(w); } } } if (!String.IsNullOrEmpty(createResult.ID)) { MultiplexedStream stream = null; Task streamTask = null; try { if (!Detach) { var parameters = new ContainerAttachParameters { Stdin = Input, Stdout = true, Stderr = true, Stream = true }; stream = await DkrClient.Containers.AttachContainerAsync(createResult.ID, Terminal, parameters, CmdletCancellationToken); streamTask = stream.CopyToConsoleAsync(Terminal, Input, CmdletCancellationToken); } if (!await DkrClient.Containers.StartContainerAsync(createResult.ID, new ContainerStartParameters())) { throw new ApplicationFailedException("The container has already started."); } if (!Detach) { await streamTask; } } finally { stream?.Dispose(); } if (RemoveAutomatically && !Detach) { await DkrClient.Containers.RemoveContainerAsync(createResult.ID, new ContainerRemoveParameters()); } else if (PassThru) { WriteObject((await ContainerOperations.GetContainersById(createResult.ID, DkrClient)).Single()); } } } }
public async void ReadStream(MultiplexedStream stream) { containerStream = stream; try { MatchEvaluator matchEval = new MatchEvaluator(AnsiEscapeHandler); while (containerStream != null) { var buffer = new byte[1024 * 4]; #if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN // unfortunately Stream.ReadAsync waiting for input blocks writing, // so we only peek to see if we have data, than wait for a bit // peek does not work on linux apparently containerStream.Peek(buffer, 1, out var peeked, out var available, out var remaining); if (available == 0) { await Task.Delay(100); continue; } #endif var result = await containerStream.ReadOutputAsync(buffer, 0, buffer.Length, readCancellationTokenSource.Token); var str = Encoding.UTF8.GetString(buffer, 0, result.Count); str = ansiEscape.Replace(str, matchEval); cleanLog += ansiEscape.Replace(str, string.Empty); int spanStart = 0; while (spanStart < str.Length) { var foundIndex = str.IndexOfAny(new[] { '\u0007', '\u0008' }, spanStart); if (foundIndex == -1) { Append(str.Substring(spanStart)); break; } if (spanStart < foundIndex) { Append(str.Substring(spanStart, foundIndex - spanStart)); } switch (str[foundIndex]) { case '\u0008': Backspace(); break; case '\u0007': OnBell(); break; } spanStart = foundIndex + 1; } if (result.EOF) { break; } } } catch (Exception e) { Debug.LogException(e); } containerStream = null; WriteLine("Process has ended, press enter key to close tab."); }
public void CloseStream() { containerStream?.Close(); containerStream?.Dispose(); containerStream = null; }
public ActiveContainer(string containerId, MultiplexedStream stream) { ContainerId = containerId; Stream = stream; }