Skip to content

Commit

Permalink
Restart ExternalScriptingShell process if exited. Add Ctrl + Q shortc…
Browse files Browse the repository at this point in the history
…ut to clear terminal output.
  • Loading branch information
bitbound committed May 19, 2021
1 parent bcaaed8 commit 65f9deb
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 63 deletions.
3 changes: 2 additions & 1 deletion Agent/Services/ExternalScriptingShell.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public ExternalScriptingShell(ConfigService configService)

public static ExternalScriptingShell GetCurrent(ScriptingShell shell, string senderConnectionId)
{
if (_sessions.TryGetValue($"{shell}-{senderConnectionId}", out var session))
if (_sessions.TryGetValue($"{shell}-{senderConnectionId}", out var session) &&
session.ShellProcess?.HasExited != true)
{
session.ProcessIdleTimeout.Stop();
session.ProcessIdleTimeout.Start();
Expand Down
128 changes: 66 additions & 62 deletions Server/Components/Devices/Terminal.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,10 @@ public partial class Terminal : AuthComponentBase, IDisposable
private int _lastCursorIndex;
private ScriptingShell _shell;

private string _terminalOpenClass;

private ElementReference _terminalInput;
private string _terminalOpenClass;
private ElementReference _terminalWindow;

[Inject]
private IModalService ModalService { get; set; }

[Inject]
private IClientAppState AppState { get; set; }

Expand All @@ -40,9 +36,6 @@ public partial class Terminal : AuthComponentBase, IDisposable
[Inject]
private IDataService DataService { get; set; }

[Inject]
private ILogger<Terminal> Logger { get; set; }

private string InputText
{
get => _inputText;
Expand All @@ -59,6 +52,33 @@ private string InputText
[Inject]
private IJsInterop JsInterop { get; set; }

[Inject]
private ILogger<Terminal> Logger { get; set; }

[Inject]
private IModalService ModalService { get; set; }
private EventCallback<SavedScript> RunQuickScript =>
EventCallback.Factory.Create<SavedScript>(this, async script =>
{
var scriptRun = new ScriptRun()
{
OrganizationID = User.OrganizationID,
RunAt = Time.Now,
SavedScriptId = script.Id,
RunOnNextConnect = false,
Initiator = User.UserName,
InputType = ScriptInputType.OneTimeScript
};

scriptRun.Devices = DataService.GetDevices(AppState.DevicesFrameSelectedDevices);

await DataService.AddScriptRun(scriptRun);

await CircuitConnection.RunScript(AppState.DevicesFrameSelectedDevices, script.Id, scriptRun.Id, ScriptInputType.OneTimeScript, false);

ToastService.ShowToast($"Running script on {scriptRun.Devices.Count} devices.");
});

[Inject]
private IToastService ToastService { get; set; }

Expand All @@ -69,13 +89,6 @@ public void Dispose()
GC.SuppressFinalize(this);
}

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
AppState.PropertyChanged += AppState_PropertyChanged;
}

protected override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
Expand All @@ -85,6 +98,12 @@ protected override Task OnAfterRenderAsync(bool firstRender)
return base.OnAfterRenderAsync(firstRender);
}

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
CircuitConnection.MessageReceived += CircuitConnection_MessageReceived;
AppState.PropertyChanged += AppState_PropertyChanged;
}
private void ApplyCompletion(PwshCommandCompletion completion)
{
try
Expand Down Expand Up @@ -172,25 +191,6 @@ private void EvaluateInputKeypress(KeyboardEventArgs ev)
}
}

private void ShowTerminalHelp()
{
ModalService.ShowModal("Terminal Help", new[]
{
"Enter terminal commands that will execute on all selected devices.",

"Tab completion is available for PowerShell Core (PSCore) and Windows PowerShell (WinPS). Tab and Shift + Tab " +
"will cycle through potential completions. Ctrl + Space will show all available completions.",

"If more than one devices is selected, the first device's file system will be used when " +
"auto-completing file and directory paths.",

"PowerShell Core is cross-platform and is available on all client operating systems. Bash is available " +
"on Windows 10 if WSL (Windows Subsystem for Linux) is installed.",

"Note: The first PS Core command or tab completion takes a few moments while the service is " +
"starting on the remote device."
});
}
private async Task EvaluateKeyDown(KeyboardEventArgs ev)
{
if (!ev.Key.Equals("Tab", StringComparison.OrdinalIgnoreCase) &&
Expand Down Expand Up @@ -238,6 +238,11 @@ private async Task EvaluateKeyDown(KeyboardEventArgs ev)

await ShowAllCompletions();
}
else if (ev.CtrlKey && ev.Key.Equals("q", StringComparison.OrdinalIgnoreCase))
{
AppState.TerminalLines.Clear();
AppState.InvokePropertyChanged(nameof(AppState.TerminalLines));
}
}

private async Task GetNextCompletion(bool forward)
Expand All @@ -261,17 +266,6 @@ private async Task ShowAllCompletions()

await CircuitConnection.GetPowerShellCompletions(_lastCompletionInput, _lastCursorIndex, CompletionIntent.ShowAll, false);
}
private void ToggleTerminalOpen()
{
if (string.IsNullOrWhiteSpace(_terminalOpenClass))
{
_terminalOpenClass = "open";
}
else
{
_terminalOpenClass = string.Empty;
}
}

private async Task ShowQuickScripts()
{
Expand All @@ -288,7 +282,7 @@ private async Task ShowQuickScripts()
return;
}


void showModal(RenderTreeBuilder builder)
{
builder.OpenComponent<QuickScriptsSelector>(0);
Expand All @@ -300,28 +294,38 @@ void showModal(RenderTreeBuilder builder)
await ModalService.ShowModal("Quick Scripts", showModal);
}

private EventCallback<SavedScript> RunQuickScript =>
EventCallback.Factory.Create<SavedScript>(this, async script =>
private void ShowTerminalHelp()
{
ModalService.ShowModal("Terminal Help", new[]
{
var scriptRun = new ScriptRun()
{
OrganizationID = User.OrganizationID,
RunAt = Time.Now,
SavedScriptId = script.Id,
RunOnNextConnect = false,
Initiator = User.UserName,
InputType = ScriptInputType.OneTimeScript
};
"Enter terminal commands that will execute on all selected devices.",

scriptRun.Devices = DataService.GetDevices(AppState.DevicesFrameSelectedDevices);
"Tab completion is available for PowerShell Core (PSCore) and Windows PowerShell (WinPS). Tab and Shift + Tab " +
"will cycle through potential completions. Ctrl + Space will show all available completions.",

await DataService.AddScriptRun(scriptRun);
"If more than one devices is selected, the first device's file system will be used when " +
"auto-completing file and directory paths.",

await CircuitConnection.RunScript(AppState.DevicesFrameSelectedDevices, script.Id, scriptRun.Id, ScriptInputType.OneTimeScript, false);
"PowerShell Core is cross-platform and is available on all client operating systems. Bash is available " +
"on Windows 10 if WSL (Windows Subsystem for Linux) is installed.",

ToastService.ShowToast($"Running script on {scriptRun.Devices.Count} devices.");
});
"Up and down arrow keys will cycle through terminal input history. Ctrl + Q will clear the output window.",

"Note: The first PS Core command or tab completion takes a few moments while the service is " +
"starting on the remote device."
});
}
private void ToggleTerminalOpen()
{
if (string.IsNullOrWhiteSpace(_terminalOpenClass))
{
_terminalOpenClass = "open";
}
else
{
_terminalOpenClass = string.Empty;
}
}
private bool TryMatchShellShortcuts()
{
var currentText = InputText?.Trim()?.ToLower();
Expand Down

0 comments on commit 65f9deb

Please sign in to comment.