-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
308 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
src/Serein.Core/Services/Network/Ssh/Console/SshConsole.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
using System.Text; | ||
|
||
using Serein.Core.Utils; | ||
|
||
using Spectre.Console; | ||
using Spectre.Console.Rendering; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshConsole : IAnsiConsole | ||
{ | ||
private readonly object _lock = new(); | ||
private readonly SshPty _sshPty; | ||
|
||
public SshConsole(SshPty sshPty) | ||
{ | ||
_sshPty = sshPty; | ||
|
||
Pipeline = new(); | ||
Input = new SshConsoleInput(_sshPty); | ||
Cursor = new SshConsoleCursor(_sshPty); | ||
Profile = new(new SshConsoleOutput(_sshPty), EncodingMap.UTF8); | ||
ExclusivityMode = new SshExclusivityMode(); | ||
|
||
if (sshPty.WidthChars > 0) | ||
Profile.Width = (int)sshPty.WidthChars; | ||
if (sshPty.HeightChars > 0) | ||
Profile.Height = (int)sshPty.HeightChars; | ||
} | ||
|
||
public Profile Profile { get; } | ||
public IAnsiConsoleCursor Cursor { get; } | ||
public IAnsiConsoleInput Input { get; } | ||
public IExclusivityMode ExclusivityMode { get; } | ||
public RenderPipeline Pipeline { get; } | ||
|
||
public void Clear(bool home) | ||
{ | ||
lock (_lock) | ||
if (home) | ||
_sshPty.Clear(); | ||
} | ||
|
||
public void Write(IRenderable renderable) | ||
{ | ||
var stringBuilder = new StringBuilder(); | ||
|
||
foreach (var segment in renderable.GetSegments(this)) | ||
{ | ||
// if (segment.IsControlCode) | ||
// { | ||
// stringBuilder.Append(segment.Text); | ||
// continue; | ||
// } | ||
|
||
stringBuilder.Append(segment.Text); | ||
|
||
// var parts = segment.Text.Normalize(NormalizationForm.FormC) | ||
} | ||
|
||
Profile.Out.Writer.Write(stringBuilder); | ||
Profile.Out.Writer.Flush(); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
src/Serein.Core/Services/Network/Ssh/Console/SshConsoleAnsiHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
|
||
using Serein.Core.Utils; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public static class SshConsoleAnsiHandler | ||
{ | ||
public static IEnumerable<ConsoleKeyInfo?> Handle(byte[] bytes) | ||
{ | ||
if (bytes.Length == 0) | ||
return []; | ||
|
||
if (bytes[0] == '\x1b' && bytes.Length > 1) | ||
return HandleAsCSISequences(bytes); | ||
|
||
var text = EncodingMap.UTF8.GetString(bytes); | ||
|
||
throw new NotImplementedException(); | ||
} | ||
|
||
private static IEnumerable<ConsoleKeyInfo?> HandleAsCSISequences(byte[] bytes) | ||
{ | ||
if (bytes.Length < 3 || bytes[1] != '[') | ||
return []; | ||
|
||
var func = Convert.ToChar(bytes[^1]); | ||
ConsoleKeyInfo? info; | ||
|
||
switch (func) | ||
{ | ||
case 'A': | ||
case 'B': | ||
case 'C': | ||
case 'D': | ||
info = new( | ||
'\x00', | ||
func switch | ||
{ | ||
'A' => ConsoleKey.UpArrow, | ||
_ => throw new NotSupportedException() | ||
}, | ||
false, | ||
false, | ||
false | ||
); | ||
if (bytes.Length == 3) | ||
return [info]; | ||
|
||
if (bytes.Length == 4) | ||
return Enumerable.Repeat(info, bytes[2]); | ||
|
||
break; | ||
|
||
} | ||
|
||
throw new NotImplementedException(); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/Serein.Core/Services/Network/Ssh/Console/SshConsoleCursor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Spectre.Console; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshConsoleCursor(SshPty sshPty) : IAnsiConsoleCursor | ||
{ | ||
private readonly SshPty _sshPty = sshPty; | ||
|
||
public void Move(CursorDirection direction, int steps) | ||
{ | ||
_sshPty.MoveCursor(direction, steps); | ||
} | ||
|
||
public void SetPosition(int column, int line) | ||
{ | ||
_sshPty.SetCursor(column, line); | ||
} | ||
|
||
public void Show(bool show) | ||
{ | ||
if (show) | ||
_sshPty.ShowCursor(); | ||
else | ||
_sshPty.HideCursor(); | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/Serein.Core/Services/Network/Ssh/Console/SshConsoleInput.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
using Spectre.Console; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshConsoleInput(SshPty sshPty) : IAnsiConsoleInput | ||
{ | ||
private readonly SshPty _sshPty = sshPty; | ||
|
||
public bool IsKeyAvailable() => true; | ||
|
||
private ConsoleKeyInfo? WaitKey(bool intercept, CancellationToken cancellationToken = default) | ||
{ | ||
var lockObj = new object(); | ||
|
||
using var handle = new EventWaitHandle(false, EventResetMode.ManualReset); | ||
cancellationToken.Register(() => handle.Set()); | ||
|
||
ConsoleKeyInfo? consoleKeyInfo = null; | ||
_sshPty.KeyRead += OnKeyRead; | ||
handle.WaitOne(); | ||
|
||
return consoleKeyInfo; | ||
|
||
void OnKeyRead(object? sender, ConsoleKeyInfo? keyInfo) | ||
{ | ||
lock (lockObj) | ||
{ | ||
_sshPty.KeyRead -= OnKeyRead; | ||
consoleKeyInfo = keyInfo; | ||
handle.Set(); | ||
|
||
if (!intercept && keyInfo.HasValue) | ||
_sshPty.Send(keyInfo.Value.KeyChar.ToString()); | ||
} | ||
} | ||
} | ||
|
||
public ConsoleKeyInfo? ReadKey(bool intercept) | ||
{ | ||
return WaitKey(intercept); | ||
} | ||
|
||
|
||
|
||
public Task<ConsoleKeyInfo?> ReadKeyAsync(bool intercept, CancellationToken cancellationToken) | ||
{ | ||
return Task.FromResult(WaitKey(intercept, cancellationToken)); | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/Serein.Core/Services/Network/Ssh/Console/SshConsoleOutput.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System.IO; | ||
using System.Text; | ||
|
||
using Spectre.Console; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshConsoleOutput(SshPty sshPty) : IAnsiConsoleOutput | ||
{ | ||
private readonly SshPty _sshPty = sshPty; | ||
|
||
public TextWriter Writer { get; } = new SshConsoleTextWriter(sshPty); | ||
|
||
public bool IsTerminal => true; | ||
|
||
public int Width => (int)_sshPty.WidthChars; | ||
|
||
public int Height => (int)_sshPty.HeightChars; | ||
|
||
public void SetEncoding(Encoding encoding) { } | ||
} |
32 changes: 32 additions & 0 deletions
32
src/Serein.Core/Services/Network/Ssh/Console/SshConsoleTextWriter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Text; | ||
|
||
using Serein.Core.Utils; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshConsoleTextWriter(SshPty sshPty) : TextWriter | ||
{ | ||
private readonly SshPty _sshPty = sshPty; | ||
|
||
public override Encoding Encoding { get; } = EncodingMap.UTF8; | ||
|
||
private readonly List<string> _buffer = []; | ||
|
||
public override void Write(string? value) | ||
{ | ||
if (value != null) | ||
lock (_buffer) | ||
_buffer.Add(value); | ||
} | ||
|
||
public override void Flush() | ||
{ | ||
lock (_buffer) | ||
{ | ||
_sshPty.Send(string.Join(string.Empty, _buffer)); | ||
_buffer.Clear(); | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/Serein.Core/Services/Network/Ssh/Console/SshExclusivityMode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
|
||
using Spectre.Console; | ||
|
||
namespace Serein.Core.Services.Network.Ssh.Console; | ||
|
||
public class SshExclusivityMode : IExclusivityMode | ||
{ | ||
public T Run<T>(Func<T> func) | ||
{ | ||
return func(); | ||
} | ||
|
||
public Task<T> RunAsync<T>(Func<Task<T>> func) | ||
{ | ||
return func(); | ||
} | ||
} |
Oops, something went wrong.