Compare commits

...
5 changed files with 141 additions and 36 deletions

No files matched your search

@@ -5,6 +5,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Fleck" Version="1.0.3" />
<PackageReference Include="MvvmLightLibs" Version="5.4.1" /> <PackageReference Include="MvvmLightLibs" Version="5.4.1" />
</ItemGroup> </ItemGroup>
@@ -1,11 +1,16 @@
using FluentTerminal.App.Services; using Fleck;
using FluentTerminal.App.Services;
using FluentTerminal.Models; using FluentTerminal.Models;
using FluentTerminal.Models.Enums; using FluentTerminal.Models.Enums;
using GalaSoft.MvvmLight; using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command; using GalaSoft.MvvmLight.Command;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq; using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace FluentTerminal.App.ViewModels namespace FluentTerminal.App.ViewModels
@@ -30,6 +35,8 @@ namespace FluentTerminal.App.ViewModels
private readonly IApplicationView _applicationView; private readonly IApplicationView _applicationView;
private readonly IDispatcherTimer _resizeOverlayTimer; private readonly IDispatcherTimer _resizeOverlayTimer;
private readonly IClipboardService _clipboardService; private readonly IClipboardService _clipboardService;
private IWebSocketConnection _webSocket;
private NamedPipeClientStream _namedPipe;
public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService, public TerminalViewModel(int id, ISettingsService settingsService, ITrayProcessCommunicationService trayProcessCommunicationService, IDialogService dialogService,
IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile, IKeyboardCommandService keyboardCommandService, ApplicationSettings applicationSettings, string startupDirectory, ShellProfile shellProfile,
@@ -187,7 +194,37 @@ namespace FluentTerminal.App.ViewModels
DefaultTitle = response.ShellExecutableName; DefaultTitle = response.ShellExecutableName;
Title = DefaultTitle; Title = DefaultTitle;
await _terminalView.ConnectToSocket(response.WebSocketUrl).ConfigureAwait(true); _namedPipe = new NamedPipeClientStream(".", response.PipeName, PipeDirection.InOut, PipeOptions.None);
if (!_namedPipe.IsConnected)
{
_namedPipe.Connect();
}
var webSocketUrl = "ws://127.0.0.1:" + response.Port;
var webSocketServer = new WebSocketServer(webSocketUrl);
webSocketServer.Start(socket =>
{
_webSocket = socket;
socket.OnOpen = () =>
{
Console.WriteLine("open");
//_connectedEvent.Set();
};
socket.OnClose = () =>
{
Console.WriteLine("closing");
_namedPipe.Close();
};
socket.OnMessage = message =>
{
var bytes = Encoding.UTF8.GetBytes(message);
_namedPipe.Write(bytes, 0, bytes.Length);
};
});
ListenToNamedPipe();
await _terminalView.ConnectToSocket(webSocketUrl).ConfigureAwait(true);
Initialized = true; Initialized = true;
} }
else else
@@ -198,6 +235,26 @@ namespace FluentTerminal.App.ViewModels
await FocusTerminal().ConfigureAwait(true); await FocusTerminal().ConfigureAwait(true);
} }
private void ListenToNamedPipe()
{
Task.Run(async () =>
{
var reader = new StreamReader(_namedPipe);
do
{
var offset = 0;
var buffer = new char[1024];
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0)
{
await _webSocket.Send(new String(buffer));
}
}
while (!reader.EndOfStream);
_webSocket.Close();
});
}
private async Task InvokeCloseRequested() private async Task InvokeCloseRequested()
{ {
if (_applicationSettings.ConfirmClosingTabs) if (_applicationSettings.ConfirmClosingTabs)
@@ -311,5 +368,34 @@ namespace FluentTerminal.App.ViewModels
ShowSearchPanel = false; ShowSearchPanel = false;
_terminalView.FocusTerminal(); _terminalView.FocusTerminal();
} }
private const int FirstDynamicPort = 49151;
public static int? GetAvailablePort()
{
var usedPorts = new List<int>();
var properties = IPGlobalProperties.GetIPGlobalProperties();
var connections = properties.GetActiveTcpConnections();
usedPorts.AddRange(connections.Where(c => c.LocalEndPoint.Port >= FirstDynamicPort).Select(c => c.LocalEndPoint.Port));
var endPoints = properties.GetActiveTcpListeners();
usedPorts.AddRange(endPoints.Where(e => e.Port >= FirstDynamicPort).Select(e => e.Port));
endPoints = properties.GetActiveUdpListeners();
usedPorts.AddRange(endPoints.Where(e => e.Port >= FirstDynamicPort).Select(e => e.Port));
usedPorts.Sort();
for (var i = FirstDynamicPort; i < UInt16.MaxValue; i++)
{
if (!usedPorts.Contains(i))
{
return i;
}
}
return null;
}
} }
} }
@@ -4,8 +4,9 @@
{ {
public int Id { get; set; } public int Id { get; set; }
public bool Success { get; set; } public bool Success { get; set; }
public string WebSocketUrl { get; set; } public int Port { get; set; }
public string Error { get; set; } public string Error { get; set; }
public string ShellExecutableName { get; set; } public string ShellExecutableName { get; set; }
public string PipeName { get; set; }
} }
} }
@@ -1,10 +1,8 @@
using Fleck; using FluentTerminal.Models;
using FluentTerminal.Models;
using FluentTerminal.Models.Requests; using FluentTerminal.Models.Requests;
using System; using System;
using System.IO; using System.IO;
using System.IO.Pipes; using System.IO.Pipes;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using static winpty.WinPty; using static winpty.WinPty;
@@ -18,7 +16,7 @@ namespace FluentTerminal.SystemTray.Services
private IntPtr _handle; private IntPtr _handle;
private Stream _stdin; private Stream _stdin;
private Stream _stdout; private Stream _stdout;
private IWebSocketConnection _webSocket; private NamedPipeServerStream _outServer;
public TerminalSession(CreateTerminalRequest request) public TerminalSession(CreateTerminalRequest request)
{ {
@@ -72,29 +70,17 @@ namespace FluentTerminal.SystemTray.Services
Id = port.Value; Id = port.Value;
_connectedEvent = new ManualResetEventSlim(false); _connectedEvent = new ManualResetEventSlim(false);
WebSocketUrl = "ws://127.0.0.1:" + port;
var webSocketServer = new WebSocketServer(WebSocketUrl); PipeName = @"LOCAL\" + Guid.NewGuid().ToString();
webSocketServer.Start(socket =>
{ _outServer = new NamedPipeServerStream(PipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None);
_webSocket = socket;
socket.OnOpen = () => StreamReader reader = new StreamReader(_outServer);
{
Console.WriteLine("open");
_connectedEvent.Set();
};
socket.OnClose = () =>
{
Console.WriteLine("closing");
ConnectionClosed?.Invoke(this, EventArgs.Empty);
};
socket.OnMessage = message =>
{
var bytes = Encoding.UTF8.GetBytes(message);
_stdin.Write(bytes, 0, bytes.Length);
};
});
ListenToStdOut(); ListenToStdOut();
ListenToNamedPipe();
} }
~TerminalSession() ~TerminalSession()
@@ -114,7 +100,9 @@ namespace FluentTerminal.SystemTray.Services
public event EventHandler ConnectionClosed; public event EventHandler ConnectionClosed;
public int Id { get; } public int Id { get; }
public string WebSocketUrl { get; }
public string PipeName { get; }
public string ShellExecutableName { get; } public string ShellExecutableName { get; }
public void Dispose() public void Dispose()
@@ -178,12 +166,18 @@ namespace FluentTerminal.SystemTray.Services
return pipe; return pipe;
} }
private void ListenToStdOut() private void ListenToNamedPipe()
{ {
new NotificationService().ShowNotification("DEBUG", "wating now");
_outServer.WaitForConnection();
new NotificationService().ShowNotification("DEBUG", "connected");
Task.Run(async () => Task.Run(async () =>
{ {
_connectedEvent.Wait(); //_connectedEvent.Wait();
var reader = new StreamReader(_stdout); var reader = new StreamReader(_outServer);
var writer = new StreamWriter(_stdin);
do do
{ {
var offset = 0; var offset = 0;
@@ -191,12 +185,34 @@ namespace FluentTerminal.SystemTray.Services
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset); var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0) if (readChars > 0)
{ {
await _webSocket.Send(new String(buffer)); writer.Write(buffer, 0, readChars);
} }
} }
while (!reader.EndOfStream); while (!reader.EndOfStream);
_webSocket.Close(); _stdin.Close();
});
}
private void ListenToStdOut()
{
Task.Run(async () =>
{
var reader = new StreamReader(_stdout);
var writer = new StreamWriter(_outServer);
do
{
var offset = 0;
var buffer = new char[1024];
var readChars = await reader.ReadAsync(buffer, offset, buffer.Length - offset);
if (readChars > 0)
{
writer.Write(buffer, 0, readChars);
}
}
while (!reader.EndOfStream);
_outServer.Close();
}); });
} }
} }
} }
@@ -35,7 +35,8 @@ namespace FluentTerminal.SystemTray.Services
{ {
Success = true, Success = true,
Id = terminal.Id, Id = terminal.Id,
WebSocketUrl = terminal.WebSocketUrl, Port = Utilities.GetAvailablePort().Value,
PipeName = terminal.PipeName,
ShellExecutableName = terminal.ShellExecutableName ShellExecutableName = terminal.ShellExecutableName
}; };
} }