diff --git a/CRCTray.cs b/CRCTray.cs new file mode 100755 index 0000000..dd39361 --- /dev/null +++ b/CRCTray.cs @@ -0,0 +1,309 @@ +using System; +using System.Windows.Forms; +using System.Diagnostics; +using System.Threading.Tasks; +using System.Collections.Generic; +using CRCTray.Communication; +using CRCTray.Helpers; + +namespace CRCTray +{ + internal class CRCTray : ApplicationContext + { + private TrayIcon trayIcon; + + // MenuStrip Items + private ToolStripItem status; + private ToolStripItem detailedStatusMenu; + // cluster commands + private ToolStripItem startMenu; + private ToolStripItem stopMenu; + private ToolStripItem deleteMenu; + // application commands + private ToolStripItem aboutMenu; + private ToolStripItem exitMenu; + private ToolStripItem settingsMenu; + // developer commands + private ToolStripItem openWebConsoleMenu; + private ToolStripItem copyOCLoginCommand; + private ToolStripItem copyOCLoginForDeveloperMenu; + private ToolStripItem copyOCLoginForKubeadminMenu; + + + // Forms + private Form settingsWindow; + private Form about; + private Form statusForm; + + private readonly double pollInterval = 5000; // 5 seconds poll interval + + // Initialize tray + public CRCTray() + { + trayIcon = new TrayIcon(); + + // start daemon + Task.Run(() => DaemonLauncher.Start(QuitApp)); + + // Keep polling status and updating the statusMenuItem + var statusPollingTimer = new System.Timers.Timer(pollInterval); + statusPollingTimer.Enabled = true; + statusPollingTimer.Elapsed += pollStatusTimerEventHandler; + + TaskHandlers.StatusChanged += UpdateClusterStatusMenu; + + SetContextMenu(); + } + + private static void pollStatusTimerEventHandler(object source, System.Timers.ElapsedEventArgs e) + { + Task.Run(TaskHandlers.Status); + } + + // populate the context menu for tray icon + private void SetContextMenu() + { + ContextMenuStrip cm = new ContextMenuStrip(); + + // Status Menu + status = cm.Items.Add(@"Unknown"); + status.Enabled = false; + + cm.Items.Add(new ToolStripSeparator()); + // Detailed status menu + detailedStatusMenu = cm.Items.Add(@"Status and Logs"); + detailedStatusMenu.Click += ShowDetailedStatusForm; + cm.Items.Add(new ToolStripSeparator()); + + // Start Menu + startMenu = cm.Items.Add(@"Start"); + startMenu.Click += StartMenu_Click; + + // Stop Menu + stopMenu = cm.Items.Add(@"Stop"); + stopMenu.Click += StopMenu_Click; + + // Delete Menu + deleteMenu = cm.Items.Add(@"Delete"); + deleteMenu.Click += DeleteMenu_Click; + + cm.Items.Add(new ToolStripSeparator()); + // Open web console menu + openWebConsoleMenu = cm.Items.Add(@"Launch Web Console"); + openWebConsoleMenu.Click += OpenWebConsoleMenu_Click; + + // Copy oc login command + copyOCLoginCommand = cm.Items.Add(@"Copy OC Login Command"); + + // Copy oc login command: developer + copyOCLoginForDeveloperMenu = (copyOCLoginCommand as ToolStripMenuItem).DropDownItems.Add(@"Developer"); + copyOCLoginForDeveloperMenu.Click += CopyOCLoginForDeveloperMenu_Click; + // Copy oc login command: kubeadmin + copyOCLoginForKubeadminMenu = (copyOCLoginCommand as ToolStripMenuItem).DropDownItems.Add(@"Kubeadmin"); + copyOCLoginForKubeadminMenu.Click += CopyOCLoginForKubeadminMenu_Click; + + cm.Items.Add(new ToolStripSeparator()); + // Settings menu + settingsMenu = cm.Items.Add(@"Settings"); + settingsMenu.Click += SettingsMenu_Click; + + cm.Items.Add(new ToolStripSeparator()); + // About menu + aboutMenu = cm.Items.Add(@"About"); + aboutMenu.Click += ShowAboutForm; + + // Exit menu + exitMenu = cm.Items.Add(@"Exit"); + exitMenu.Click += ExitMenu_Click; + + // set context menu on trayicon + trayIcon.ContextMenuStrip = cm; + + // enable items + aboutMenu.Enabled = true; + detailedStatusMenu.Enabled = true; + } + + private void SettingsMenu_Click(object sender, EventArgs e) + { + if (settingsWindow == null) + settingsWindow = new CrcSettingsForm(); + + if (!settingsWindow.Visible) + settingsWindow.Show(); + + settingsWindow.Focus(); + } + + async private void CopyOCLoginForKubeadminMenu_Click(object sender, EventArgs e) + { + var consoleResult = await Task.Run(TaskHandlers.LoginForKubeadmin); + + if (consoleResult != null) + { + if (consoleResult.Success) + Clipboard.SetText(string.Format("oc.exe login -u kubeadmin -p {0} {1}", consoleResult.ClusterConfig.KubeAdminPass, consoleResult.ClusterConfig.ClusterAPI)); + else + TrayIcon.NotifyError(@"Could not find credentials, is CRC runnning?"); + } + } + + async private void CopyOCLoginForDeveloperMenu_Click(object sender, EventArgs e) + { + var consoleResult = await Task.Run(TaskHandlers.LoginForDeveloper); + + if (consoleResult != null) + { + if (consoleResult.Success) + Clipboard.SetText(string.Format("oc.exe login -u developer -p developer {0}", consoleResult.ClusterConfig.ClusterAPI)); + else + TrayIcon.NotifyError(@"Could not find credentials, is CRC running?"); + } + } + + async private void OpenWebConsoleMenu_Click(object sender, EventArgs e) + { + var consoleResult = await Task.Run(TaskHandlers.WebConsole); + + if (consoleResult != null) + { + if (consoleResult.Success) + Process.Start(consoleResult.ClusterConfig.WebConsoleURL); + else + TrayIcon.NotifyError(@"Could not open web console, is CRC running?"); + } + } + + async private void DeleteMenu_Click(object sender, EventArgs e) + { + TrayIcon.NotifyWarn(@"Deleting Cluster"); + var deleteResult = await Task.Run(TaskHandlers.Delete); + + if (deleteResult != null) + { + if (deleteResult.Success) + TrayIcon.NotifyInfo(@"Cluster deleted"); + else + TrayIcon.NotifyWarn(@"Could not delete the cluster. Please check detailed atatus"); + } + } + + async private void StopMenu_Click(object sender, EventArgs e) + { + TrayIcon.NotifyInfo(@"Stopping Cluster"); + var stopResult = await Task.Run(TaskHandlers.Stop); + + if (stopResult != null) + { + if (stopResult.Success) + TrayIcon.NotifyInfo(@"Cluster Stopped"); + else + TrayIcon.NotifyWarn(@"Cluster did not stop. Please check detailed status"); + } + } + + async private void StartMenu_Click(object sender, EventArgs e) + { + // Check using get-config if pullSecret is configured + var configs = await Task.Run(TaskHandlers.ConfigView); + if (configs.Configs.PullSecretFile == String.Empty) + { + var pullSecretForm = new PullSecretPickerForm(); + var pullSecretPath = pullSecretForm.ShowFilePicker(); + if (pullSecretPath == String.Empty) + { + TrayIcon.NotifyWarn(@"No Pull Secret was provided, Cannot start cluster without pull secret."); + return; + } + Dictionary pullSecretConfig = new Dictionary + { + ["pull-secret-file"] = pullSecretPath + }; + await Task.Run(() => TaskHandlers.SetConfig(pullSecretConfig)); + } + + TrayIcon.NotifyInfo(@"Starting Cluster"); + var startResult = await Task.Run(TaskHandlers.Start); + if (startResult == null) + { + return; + } + + if (startResult.KubeletStarted) + TrayIcon.NotifyInfo(@"CodeReady Containers Cluster has started"); + else + TrayIcon.NotifyWarn(@"Cluster did not start. Please check detailed status"); + } + + private void ExitMenu_Click(object sender, EventArgs e) + { + QuitApp(); + } + + private void ShowAboutForm(object sender, EventArgs e) + { + if (about == null) + about = new AboutForm(); + + if (!about.Visible) + about.Show(); + + about.Focus(); + } + + private void ShowDetailedStatusForm(object sender, EventArgs e) + { + if (statusForm == null) + statusForm = new StatusForm(); + + if (!statusForm.Visible) + statusForm.Show(); + + statusForm.Focus(); + } + + private void UpdateClusterStatusMenu(StatusResult statusResult) + { + status.Text = statusResult.CrcStatus; + + // enable based on status + //startMenu.Enabled = false; + + // switch (statusResult.CrcStatus) + // { + // case "Stopped": + // stopMenu.Enabled = false; + // deleteMenu.Enabled = true; + + // openWebConsoleMenu.Enabled = false; + // copyOCLoginCommand.Enabled = false; + // copyOCLoginForDeveloperMenu.Enabled = false; + // copyOCLoginForKubeadminMenu.Enabled = false; + + // break; + // case "Starting": + // case "Started": + // startMenu.Enabled = false; + + // deleteMenu.Enabled = true; + + // stopMenu.Enabled = true; + // openWebConsoleMenu.Enabled = true; + // copyOCLoginCommand.Enabled = true; + // copyOCLoginForDeveloperMenu.Enabled = true; + // copyOCLoginForKubeadminMenu.Enabled = true; + + // break; + // } + ////} + } + + private void QuitApp() + { + trayIcon.Visible = false; + trayIcon.Dispose(); + Environment.Exit(-1); + } + } +} + diff --git a/Communication/DaemonCommander.cs b/Communication/DaemonCommander.cs index 6488da9..6aae047 100755 --- a/Communication/DaemonCommander.cs +++ b/Communication/DaemonCommander.cs @@ -1,58 +1,56 @@ using System; using System.Text; using System.Net; -using System.Net.Sockets; +using System.Net.Http; using System.Text.Json; using System.Text.Json.Serialization; -using System.Windows.Forms; +using System.Threading; +using System.Threading.Tasks; +using HttpOverStream.Client; +using HttpOverStream.NamedPipe; + namespace CRCTray.Communication { static class DaemonCommander { - static private string socketPath = string.Format("{0}\\.crc\\crc.sock", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + private static readonly string _daemonHTTPNamedPipe = "crc-http"; + private static readonly string _apiPath = "/api"; - public class DaemonException : Exception - { - public DaemonException(string message) : base(message) - { - } - } - - private static T getResultsForBasicCommand(string command) + private static T getResultsForBasicCommand(string command, int timeout = 20) { - var output = SendBasicCommand(command); - var options = new JsonSerializerOptions - { - IgnoreNullValues = true - }; - var status = JsonSerializer.Deserialize(output, options); - if (status.Success) - { - return JsonSerializer.Deserialize(output, options); - } - throw new DaemonException(status.Error); + return JsonSerializer.Deserialize(SendBasicCommand(command, timeout)); } public static StatusResult Status() { return getResultsForBasicCommand(BasicCommands.Status); + + // 200 status command was successful (json returned) + // 500 could refer to VM not existing } public static VersionResult Version() { return getResultsForBasicCommand(BasicCommands.Version); + + // 200 } public static StartResult Start() { - return getResultsForBasicCommand(BasicCommands.Start); + return getResultsForBasicCommand(BasicCommands.Start, 300); + + // 200 + // 500 could refer to VM already starting } public static StopResult Stop() { - return getResultsForBasicCommand(BasicCommands.Stop); + return getResultsForBasicCommand(BasicCommands.Stop, 120); + + // 500 could refer to VM already stopping } public static DeleteResult Delete() @@ -67,68 +65,76 @@ public static ConsoleResult ConsoleUrl() public static ConfigResult ConfigView() { - return getResultsForBasicCommand(BasicCommands.Config); + return getResultsForBasicCommand(BasicCommands.ConfigGet); } public static SetUnsetConfig SetConfig(ConfigSetCommand cmd) { - return JsonSerializer.Deserialize(SendCommand(cmd)); - } + var result = postResponse(BasicCommands.ConfigSet, JsonSerializer.Serialize(cmd.args), 30); + return JsonSerializer.Deserialize(result.Result); + } public static SetUnsetConfig UnsetConfig(ConfigUnsetCommand cmd) { - return JsonSerializer.Deserialize(SendCommand(cmd)); + var result = postResponse(BasicCommands.ConfigSet, JsonSerializer.Serialize(cmd.args), 30); + return JsonSerializer.Deserialize(result.Result); } - public static Logs GetLogs() + public static LogsResult GetLogs() { - return getResultsForBasicCommand(BasicCommands.Logs); + return getResultsForBasicCommand(BasicCommands.Logs); } - private static string SendBasicCommand(string command) - { - var cmd = JsonSerializer.Serialize(new BasicCommand(command)); - return getSocketResponse(cmd); - } - - private static string SendCommand(ConfigSetCommand command) + private static string SendBasicCommand(string command, int timeout) { - JsonSerializerOptions options = new JsonSerializerOptions(); - options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; - var cmd = JsonSerializer.Serialize(command, options); - - return getSocketResponse(cmd); + return getResponse(command, timeout).Result; } - private static string SendCommand(ConfigUnsetCommand command) - { - JsonSerializerOptions options = new JsonSerializerOptions(); - options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; - var cmd = JsonSerializer.Serialize(command, options); - - return getSocketResponse(cmd); - } + private static async Task postResponse(string cmd, string content, int timeout) + { + try + { + var httpClient = new NamedPipeHttpClientBuilder(_daemonHTTPNamedPipe) + .WithPerRequestTimeout(TimeSpan.FromSeconds(timeout)) + .Build(); + + var httpContent = new StringContent(content, Encoding.UTF8, "application/json"); + string command = String.Format("{0}/{1}", _apiPath, cmd); + HttpResponseMessage response = await httpClient.PostAsync(command, httpContent); + + // Allow 500 + //response.EnsureSuccessStatusCode(); + + return await response.Content.ReadAsStringAsync(); + } + + catch (Exception e) + { + // re-throw to let the caller deal with the specific error codes + throw e; + } + } - private static string getSocketResponse(string cmd) + private static async Task getResponse(string cmd, int timeout) { try { - Socket daemonSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); - UnixEndPoint daemonSocketEp = new UnixEndPoint(socketPath); + var httpClient = new NamedPipeHttpClientBuilder(_daemonHTTPNamedPipe) + .WithPerRequestTimeout(TimeSpan.FromSeconds(timeout)) + .Build(); + + string command = String.Format("{0}/{1}", _apiPath, cmd); + HttpResponseMessage response = await httpClient.GetAsync(command); - var resp = new byte[16 * 1024]; - daemonSocket.Connect(daemonSocketEp); - byte[] msg = Encoding.ASCII.GetBytes(cmd); - daemonSocket.Send(msg); - daemonSocket.Receive(resp); + // Allow 500 + //response.EnsureSuccessStatusCode(); - var result = Encoding.ASCII.GetString(resp); - return result.Replace("\0", string.Empty); + return await response.Content.ReadAsStringAsync(); } - catch (SocketException e) + catch (Exception e) { - Console.WriteLine("Exception occured"); + // re-throw to let the caller deal with the specific error codes throw e; } } diff --git a/Communication/Enums.cs b/Communication/Enums.cs index 039abb6..021e27f 100755 --- a/Communication/Enums.cs +++ b/Communication/Enums.cs @@ -12,9 +12,9 @@ static class BasicCommands internal const string Delete = "delete"; internal const string ConsoleUrl = "webconsoleurl"; - internal const string Config = "getconfig"; - + internal const string ConfigGet = "config/get"; + internal const string ConfigSet = "config/set"; + internal const string ConfigUnset = "config/unset"; internal const string Logs = "logs"; } - -} +} \ No newline at end of file diff --git a/Communication/ResponseClasses.cs b/Communication/ResponseClasses.cs index 888ef53..c1527a5 100755 --- a/Communication/ResponseClasses.cs +++ b/Communication/ResponseClasses.cs @@ -20,6 +20,12 @@ public class StatusResult public bool Success { get; set; } } + public class LogsResult + { + public bool Success { get; set; } + public string[] Messages { get; set; } + } + public class StartResult { public string Name { get; set; } @@ -163,9 +169,4 @@ struct SetUnsetConfig public string[] Properties { get; set; } } - struct Logs - { - public bool Success { get; set; } - public string[] Messages { get; set; } - } } \ No newline at end of file diff --git a/Communication/UnixEndPoint.cs b/Communication/UnixEndPoint.cs deleted file mode 100755 index 7ae8d99..0000000 --- a/Communication/UnixEndPoint.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System.Text; -using System.Net.Sockets; - - -namespace System.Net -{ - public class UnixEndPoint : EndPoint - { - string filename; - - public UnixEndPoint(string filename) - { - if (string.IsNullOrEmpty(filename)) - throw new ArgumentException("Cannot be null or empty.", "filename"); - this.filename = filename; - } - - public string Filename - { - get - { - return (filename); - } - set - { - filename = value; - } - } - - public override AddressFamily AddressFamily - { - get { return AddressFamily.Unix; } - } - - public override EndPoint Create(SocketAddress socketAddress) - { - /* - * Should also check this - * - int addr = (int) AddressFamily.Unix; - if (socketAddress [0] != (addr & 0xFF)) - throw new ArgumentException ("socketAddress is not a unix socket address."); - if (socketAddress [1] != ((addr & 0xFF00) >> 8)) - throw new ArgumentException ("socketAddress is not a unix socket address."); - */ - - if (socketAddress.Size == 2) - { - // Empty filename. - // Probably from RemoteEndPoint which on linux does not return the file name. - UnixEndPoint uep = new UnixEndPoint("a"); - uep.filename = ""; - return uep; - } - int size = socketAddress.Size - 2; - byte[] bytes = new byte[size]; - for (int i = 0; i < bytes.Length; i++) - { - bytes[i] = socketAddress[i + 2]; - // There may be junk after the null terminator, so ignore it all. - if (bytes[i] == 0) - { - size = i; - break; - } - } - - string name = Encoding.UTF8.GetString(bytes, 0, size); - return new UnixEndPoint(name); - } - - public override SocketAddress Serialize() - { - byte[] bytes = Encoding.UTF8.GetBytes(filename); - SocketAddress sa = new SocketAddress(AddressFamily, 2 + bytes.Length + 1); - // sa [0] -> family low byte, sa [1] -> family high byte - for (int i = 0; i < bytes.Length; i++) - sa[2 + i] = bytes[i]; - - //NULL suffix for non-abstract path - sa[2 + bytes.Length] = 0; - - return sa; - } - - public override string ToString() - { - return (filename); - } - - public override int GetHashCode() - { - return filename.GetHashCode(); - } - - public override bool Equals(object o) - { - UnixEndPoint other = o as UnixEndPoint; - if (other == null) - return false; - - return (other.filename == filename); - } - } -} \ No newline at end of file diff --git a/Forms/AboutForm.cs b/Forms/AboutForm.cs index c29962f..d30d0d3 100755 --- a/Forms/AboutForm.cs +++ b/Forms/AboutForm.cs @@ -1,8 +1,10 @@ using System; using System.Drawing; using System.Windows.Forms; +using System.Threading.Tasks; using CRCTray.Communication; using CRCTray.Helpers; +using System.Diagnostics; namespace CRCTray { @@ -25,16 +27,16 @@ private void AboutForm_Load(object sender, EventArgs e) Shown += GetVersion; } - private void GetVersion(object sender, EventArgs e) + private async void GetVersion(object sender, EventArgs e) { - version = TaskHandlers.Version(); + version = await Task.Run(TaskHandlers.Version); if (version.Success) { CrcVersionLabel.Text = String.Format("{0}+{1}", version.CrcVersion, version.CommitSha); OcpVersion.Text = version.OpenshiftVersion; } else { - DisplayMessageBox.Warn("Unable to fetch version information from daemon"); + TrayIcon.NotifyWarn("Unable to fetch version information from daemon"); } } private void AboutForm_FormClosing(object sender, FormClosingEventArgs e) @@ -49,12 +51,12 @@ private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs var v = crcVersionWithGitSha[0].Substring(0, crcVersionWithGitSha[0].Length - 2); var docsUrl = string.Format("https://access.redhat.com/documentation/en-us/red_hat_codeready_containers/{0}/", v); - System.Diagnostics.Process.Start(docsUrl); + Process.Start(docsUrl); } private void linkLabel2_LinkClicked_1(object sender, LinkLabelLinkClickedEventArgs e) { - System.Diagnostics.Process.Start("https://github.com/code-ready/tray-windows"); + Process.Start("https://github.com/code-ready/tray-windows"); } } } diff --git a/Forms/CrcSettingsForm.cs b/Forms/CrcSettingsForm.cs index 61d6aeb..073cb55 100755 --- a/Forms/CrcSettingsForm.cs +++ b/Forms/CrcSettingsForm.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.Linq; using System.Windows.Forms; +using System.Threading.Tasks; using CRCTray.Communication; using CRCTray.Helpers; @@ -22,11 +23,11 @@ public CrcSettingsForm() getConfigurationAndResetChanged(); } - private void getConfigurationAndResetChanged() + private async void getConfigurationAndResetChanged() { this.changedConfigs = new Dictionary(); this.configsNeedingUnset = new List(); - currentConfig = TaskHandlers.ConfigView(); + currentConfig = await Task.Run(TaskHandlers.ConfigView); loadConfigurationValues(currentConfig); configChanged = false; } @@ -139,24 +140,24 @@ private void RefreshButton_Click(object sender, EventArgs e) } // Apply button on properties tab - private void ApplyButton_Click(object sender, EventArgs e) + private async void ApplyButton_Click(object sender, EventArgs e) { - if (this.configChanged && changedConfigs.Count > 0) + if (this.configChanged && changedConfigs.Count > 0) { - SetUnsetConfig r = TaskHandlers.SetConfig(changedConfigs); + SetUnsetConfig r = await Task.Run(() => TaskHandlers.SetConfig(changedConfigs)); if (r.Error == String.Empty) - DisplayMessageBox.Info("Properties configured: " + String.Join(",", r.Properties), "CodeReady Containers - Settings Applied"); + TrayIcon.NotifyInfo("Settings Applied"); else - DisplayMessageBox.Error(r.Error); + TrayIcon.NotifyError(r.Error); } if (this.configsNeedingUnset.Count > 0) - { - SetUnsetConfig r = TaskHandlers.UnsetConfig(configsNeedingUnset); + { + SetUnsetConfig r = await Task.Run(() => TaskHandlers.UnsetConfig(configsNeedingUnset)); if (r.Error == String.Empty) - DisplayMessageBox.Info("Properties unset: " + String.Join(",", r.Properties), "CodeReady Containers - Settings Applied"); + TrayIcon.NotifyInfo("Settings Applied"); else - DisplayMessageBox.Error(r.Error); + TrayIcon.NotifyError(r.Error); } // Load the configs again and reset the change trackers diff --git a/Forms/PullSecretPickerForm.cs b/Forms/PullSecretPickerForm.cs index 1c61b0e..8ab15d0 100755 --- a/Forms/PullSecretPickerForm.cs +++ b/Forms/PullSecretPickerForm.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using CRCTray.Helpers; namespace CRCTray { @@ -57,7 +58,7 @@ private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs } catch (Exception ex) { - Helpers.DisplayMessageBox.Warn(string.Format("Cannot open URL in default browser {0}", ex.ToString())); + TrayIcon.NotifyWarn(string.Format("Cannot open URL in default browser {0}", ex.ToString())); } } } diff --git a/Forms/StatusForm.cs b/Forms/StatusForm.cs index 4b65b9e..b001468 100755 --- a/Forms/StatusForm.cs +++ b/Forms/StatusForm.cs @@ -3,101 +3,118 @@ using System.Drawing; using System.Windows.Forms; using System.Threading.Tasks; -using CRCTray.Communication; using CRCTray.Helpers; +using CRCTray.Communication; namespace CRCTray { public partial class StatusForm : Form { + delegate void UpdateStatusCallback(StatusResult status); + Timer UpdateStatusTimer; + public StatusForm() { InitializeComponent(); + + TaskHandlers.StatusReceived += UpdateStatus; } private void StatusForm_Load(object sender, EventArgs e) { + // deal with async behaviour + const string _3dot = "..."; + CrcStatus.Text = _3dot; + OpenShiftStatus.Text = _3dot; + DiskUsage.Text = _3dot; + CacheUsage.Text = _3dot; + CacheFolder.Text = _3dot; + Bitmap bm = new Bitmap(Resource.ocp_logo); Icon = Icon.FromHandle(bm.GetHicon()); Text = @"Status and Logs"; - Console.WriteLine("For loaded"); - + this.FormClosing += StatusForm_Closing; - // Update logs - GetStatus(); - UpdateLogs(); - - var timer = new Timer(); - timer.Interval = 3000; // 3 seconds - timer.Enabled = true; - timer.Tick += Timer_Tick; + this.Activated += StatusForm_Activated; + + UpdateStatusTimer = new Timer(); + UpdateStatusTimer.Interval = 3000; // 3 seconds + UpdateStatusTimer.Enabled = true; + UpdateStatusTimer.Tick += Timer_Tick; + } + + private void StatusForm_Activated(object sender, EventArgs e) + { + UpdateStatusTimer.Enabled = true; } private void Timer_Tick(object sender, EventArgs e) { - Console.WriteLine("Updating logs"); - UpdateLogs(); - GetStatus(); + Console.WriteLine("Updating status and logs"); + + // Run as task to make sure it doesn't block this window + Task.Run(TaskHandlers.Status); + GetLogs(); } - async private void GetStatus() + private void StatusForm_Closing(object sender, FormClosingEventArgs e) + { + this.Hide(); + UpdateStatusTimer.Enabled = false; + e.Cancel = true; + } + + private void UpdateStatus(StatusResult status) { - var status = await Task.Run(() => TaskHandlers.Status()); if (status != null) { - var cacheFolderPath = string.Format("{0}\\.crc\\cache", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); - Console.WriteLine(status); - Console.WriteLine(status.OpenshiftStatus); - if (status.Error != "") + if (CrcStatus.InvokeRequired) { - CrcStatus.Text = ErrorText(status); - OpenShiftStatus.Text = "Unknown"; + UpdateStatusCallback c = UpdateStatus; + Invoke(c, status); } - else if (status.CrcStatus != "") + else { - CrcStatus.Text = status.CrcStatus; - OpenShiftStatus.Text = StatusText(status); + var cacheFolderPath = string.Format("{0}\\.crc\\cache", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)); + + if (status.CrcStatus != "") + CrcStatus.Text = status.CrcStatus; + + if (status.OpenshiftStatus != "") + OpenShiftStatus.Text = StatusText(status); + + DiskUsage.Text = string.Format("{0} of {1} (Inside the CRC VM)", FileSize.HumanReadable(status.DiskUse), FileSize.HumanReadable(status.DiskSize)); + CacheUsage.Text = FileSize.HumanReadable(GetFolderSize.SizeInBytes(cacheFolderPath)); + CacheFolder.Text = cacheFolderPath; } - DiskUsage.Text = string.Format("{0} of {1} (Inside the CRC VM)", FileSize.HumanReadable(status.DiskUse), FileSize.HumanReadable(status.DiskSize)); - CacheUsage.Text = FileSize.HumanReadable(GetFolderSize.SizeInBytes(cacheFolderPath)); - CacheFolder.Text = cacheFolderPath; } } - + private static string StatusText(StatusResult status) { var ret = ""; - if (!string.IsNullOrEmpty(status.OpenshiftStatus)) + if (!string.IsNullOrEmpty(status.OpenshiftStatus)) ret += status.OpenshiftStatus; if (!string.IsNullOrEmpty(status.OpenshiftVersion)) ret += string.Format(" (v{0})", status.OpenshiftVersion); return ret; } - private static string ErrorText(StatusResult status) + + private async void GetLogs() { - if (status.Error.Length > 200) + var logs = await Task.Run(TaskHandlers.GetDaemonLogs); + if (logs != null) { - return status.Error.Substring(0, Math.Min(200, status.Error.Length)) + " ..."; - } - return status.Error; - } + var messages = string.Join("\r\n", logs.Messages); - private void StatusForm_Closing(object sender, FormClosingEventArgs e) - { - this.Hide(); - e.Cancel = true; - } + if (logsTextBox.Text == messages) + return; - private void UpdateLogs() - { - var logs = TaskHandlers.GetDaemonLogs(); - var messages = string.Join("\r\n", logs.Messages); - if (logsTextBox.Text == messages) - return; - logsTextBox.Text = messages; - logsTextBox.SelectionStart = logsTextBox.Text.Length; - logsTextBox.ScrollToCaret(); + logsTextBox.Text = messages; + logsTextBox.SelectionStart = logsTextBox.Text.Length; + logsTextBox.ScrollToCaret(); + } } } @@ -136,7 +153,7 @@ public static long SizeInBytes(string path) } catch (Exception e) { - DisplayMessageBox.Error(string.Format("Unexpected Error, did you run 'crc setup'? Error: {0}", e.Message)); + TrayIcon.NotifyError(string.Format("Unexpected Error, did you run 'crc setup'? Error: {0}", e.Message)); } return size; } diff --git a/Helpers/DaemonLauncher.cs b/Helpers/DaemonLauncher.cs new file mode 100755 index 0000000..9d90215 --- /dev/null +++ b/Helpers/DaemonLauncher.cs @@ -0,0 +1,49 @@ +using System; +using System.Diagnostics; + +namespace CRCTray.Helpers +{ + class DaemonLauncher + { + internal static void Start(Action quitFunc) + { + // TODO: Action to be replaced with an event 'Stopped' + + var process = new Process(); + process.StartInfo.CreateNoWindow = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.FileName = string.Format("{0}\\{1}\\crc.exe", + Environment.GetEnvironmentVariable("ProgramW6432"), @"CodeReady Containers"); +#if DEBUG + process.StartInfo.FileName = string.Format("{0}\\bin\\crc.exe", Environment.GetEnvironmentVariable("GOPATH")); +#endif + process.StartInfo.Arguments = @"daemon --watchdog"; + process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + try + { + process.Start(); + System.IO.StreamWriter daemonStdinWriter = process.StandardInput; + } + catch (Exception e) + { + TrayIcon.NotifyError(@"Cannot start the daemon, Check the logs and restart the application"); + + quitFunc(); + } + + process.WaitForExit(); + if (process.ExitCode == 2) + { + TrayIcon.NotifyError(@"Setup incomplete, Open a terminal, run 'crc setup', and start again this application."); + } + else + { + TrayIcon.NotifyError(@"Daemon crashed, check the logs and restart the application"); + } + + quitFunc(); + } + } +} diff --git a/Helpers/DisplayMessageBox.cs b/Helpers/DisplayMessageBox.cs deleted file mode 100755 index 180cea8..0000000 --- a/Helpers/DisplayMessageBox.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Windows.Forms; - -namespace CRCTray.Helpers -{ - class DisplayMessageBox - { - private static string caption = @"CodeReady Containers"; - public static void Error(string message) - { - MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error); - } - - public static void Warn(string message) - { - MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Warning); - } - - public static void Info(string message, string title) - { - MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Information); - } - } -} diff --git a/Helpers/Handlers.cs b/Helpers/Handlers.cs index bfb516b..8ab0aa3 100755 --- a/Helpers/Handlers.cs +++ b/Helpers/Handlers.cs @@ -4,98 +4,138 @@ namespace CRCTray.Helpers { + // Events for status command + public delegate void StatusChangedHandler(StatusResult result); + public delegate void StatusReceivedHandler(StatusResult result); + + // Events for commands + public delegate void LogsReceivedHandler(LogsResult result); + public delegate void StartReceivedHandler(StartResult result); + public delegate void StopReceivedHandler(StopResult result); + public delegate void DeleteReceivedHandler(DeleteResult result); + static class TaskHandlers { - private static T getResultsOrShowMessage(Func function) + private static string _previousStatus; + private static readonly object _statusChangeLock = new object(); + + public static event StatusChangedHandler StatusChanged; + public static event StatusReceivedHandler StatusReceived; + public static event LogsReceivedHandler LogsReceived; + public static event StartReceivedHandler StartReceived; + public static event StopReceivedHandler StopReceived; + public static event DeleteReceivedHandler DeleteReceived; + + private static T getResultsOrDefault(Func function) { try { return function(); } - catch (Exception ex) + catch(Exception e) { - DisplayMessageBox.Error(ex.Message); return default; } } - private static T getResultsOrShowMessage(Func function, TArgs args) + private static T getResultsOrDefault(Func function, TArgs args) { try { return function(args); } - catch (Exception ex) + catch(Exception e) { - DisplayMessageBox.Error(ex.Message); return default; } } public static VersionResult Version() { - return getResultsOrShowMessage(DaemonCommander.Version); + return getResultsOrDefault(DaemonCommander.Version); } public static StartResult Start() { - return getResultsOrShowMessage(DaemonCommander.Start); + StartResult result = getResultsOrDefault(DaemonCommander.Start); + + if (StartReceived != null && result != null) + StartReceived(result); + + return result; } public static StopResult Stop() { - return getResultsOrShowMessage(DaemonCommander.Stop); + StopResult result = getResultsOrDefault(DaemonCommander.Stop); + + if (StopReceived != null && result != null) + StopReceived(result); + + return result; } public static DeleteResult Delete() { - return getResultsOrShowMessage(DaemonCommander.Delete); + DeleteResult result = getResultsOrDefault(DaemonCommander.Delete); + + if (DeleteReceived != null && result != null) + DeleteReceived(result); + + return result; } public static StatusResult Status() { - try - { - return DaemonCommander.Status(); - } - catch (DaemonCommander.DaemonException ex) - { - StatusResult status = new StatusResult(); - status.Success = false; - status.Error = ex.Message; - return status; - } - catch (Exception ex) + StatusResult result = getResultsOrDefault(DaemonCommander.Status); + if (result == null) + return null; + + if (StatusReceived != null) + StatusReceived(result); + + lock (_statusChangeLock) { - StatusResult status = new StatusResult(); - status.Success = false; - status.Error = ex.ToString(); - return status; + if (StatusChanged != null && _previousStatus != result.OpenshiftStatus) + StatusChanged(result); + + _previousStatus = result.OpenshiftStatus; } + return result; + } + + public static LogsResult GetDaemonLogs() + { + LogsResult result = getResultsOrDefault(DaemonCommander.GetLogs); + + if (LogsReceived != null && result != null) + LogsReceived(result); + + return result; } public static ConsoleResult WebConsole() { - return getResultsOrShowMessage(DaemonCommander.ConsoleUrl); + return getResultsOrDefault(DaemonCommander.ConsoleUrl); } public static ConfigResult ConfigView() { - return getResultsOrShowMessage(DaemonCommander.ConfigView); + return getResultsOrDefault(DaemonCommander.ConfigView); } public static SetUnsetConfig SetConfig(Dictionary cfg) { // TODO: unnecessary wrapping var config = new ConfigSetCommand(cfg); - return getResultsOrShowMessage(DaemonCommander.SetConfig, config); + return getResultsOrDefault(DaemonCommander.SetConfig, config); } public static SetUnsetConfig UnsetConfig(List cfg) { // TODO: unnecessary wrapping var config = new ConfigUnsetCommand(cfg); - return getResultsOrShowMessage(DaemonCommander.UnsetConfig, config); + return getResultsOrDefault(DaemonCommander.UnsetConfig, config); } public static ConsoleResult LoginForDeveloper() @@ -107,20 +147,5 @@ public static ConsoleResult LoginForKubeadmin() { return WebConsole(); } - - public static Logs GetDaemonLogs() - { - try - { - return DaemonCommander.GetLogs(); - } - catch (Exception ex) - { - Logs logs = new Logs(); - logs.Success = true; - logs.Messages = new string[1] { ex.ToString() }; - return logs; - } - } } } \ No newline at end of file diff --git a/Helpers/TrayIcon.cs b/Helpers/TrayIcon.cs new file mode 100755 index 0000000..69b5915 --- /dev/null +++ b/Helpers/TrayIcon.cs @@ -0,0 +1,92 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace CRCTray.Helpers +{ + class TrayIcon : IDisposable + { + //tray Icon + private static NotifyIcon notifyIcon; + + public TrayIcon() + { + Bitmap bm = new Bitmap(Resource.ocp_logo); + notifyIcon = new NotifyIcon + { + Icon = Icon.FromHandle(bm.GetHicon()), + Visible = true + }; + + notifyIcon.MouseClick += NotifyIcon_MouseClick; + } + + private void NotifyIcon_MouseClick(object sender, MouseEventArgs e) + { + ShowContextMenu(); + } + + public static void NotifyError(string message) + { + if (String.IsNullOrEmpty(message)) + message = "Error occurred"; + Notification(message, ToolTipIcon.Error); + } + + public static void NotifyWarn(string message) + { + Notification(message, ToolTipIcon.Warning); + } + + public static void NotifyInfo(string message) + { + Notification(message, ToolTipIcon.Info); + } + + private static void Notification(string msg, ToolTipIcon toolTipIcon) + { + if (notifyIcon == null) + return; // prevent use before being created + + notifyIcon.BalloonTipIcon = toolTipIcon; + notifyIcon.BalloonTipText = msg; + + notifyIcon.ShowBalloonTip(5); + } + + public void ShowContextMenu() + { + typeof(NotifyIcon).GetMethod("ShowContextMenu", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(notifyIcon, null); + } + + public void Dispose() + { + notifyIcon.Dispose(); + } + + public ContextMenuStrip ContextMenuStrip + { + set + { + notifyIcon.ContextMenuStrip = value; + } + get + { + return notifyIcon.ContextMenuStrip; + } + } + + public bool Visible + { + set + { + notifyIcon.Visible = value; + } + get + { + return notifyIcon.Visible; + } + } + } + +} diff --git a/Libraries/HttpOverStream.Client.dll b/Libraries/HttpOverStream.Client.dll new file mode 100755 index 0000000..f0300fd Binary files /dev/null and b/Libraries/HttpOverStream.Client.dll differ diff --git a/Libraries/HttpOverStream.NamedPipe.dll b/Libraries/HttpOverStream.NamedPipe.dll new file mode 100755 index 0000000..e252235 Binary files /dev/null and b/Libraries/HttpOverStream.NamedPipe.dll differ diff --git a/Libraries/HttpOverStream.dll b/Libraries/HttpOverStream.dll new file mode 100755 index 0000000..c6d89d7 Binary files /dev/null and b/Libraries/HttpOverStream.dll differ diff --git a/Libraries/System.Runtime.CompilerServices.Unsafe.dll b/Libraries/System.Runtime.CompilerServices.Unsafe.dll new file mode 100755 index 0000000..0b45903 Binary files /dev/null and b/Libraries/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/Libraries/System.Threading.Tasks.Extensions.dll b/Libraries/System.Threading.Tasks.Extensions.dll new file mode 100755 index 0000000..63bf0ed Binary files /dev/null and b/Libraries/System.Threading.Tasks.Extensions.dll differ diff --git a/Program.cs b/Program.cs index fd33d97..dd879eb 100755 --- a/Program.cs +++ b/Program.cs @@ -1,15 +1,10 @@ using System; using System.IO; using System.Windows.Forms; -using System.Drawing; -using System.Diagnostics; -using System.Threading.Tasks; -using System.Collections.Generic; -using CRCTray.Communication; -using CRCTray.Helpers; namespace CRCTray { + static class Program { /// @@ -22,374 +17,15 @@ static void Main() // http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/ if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware(); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); - Application.Run(new TrayContext()); + Application.Run(new CRCTray()); } + // Fix for blurry controls taken from // http://crsouza.com/2015/04/13/how-to-fix-blurry-windows-forms-windows-in-high-dpi-settings/ [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern bool SetProcessDPIAware(); } - - internal class TrayContext : ApplicationContext - { - //tray Icon - private NotifyIcon notifyIcon; - - // MenuStrip Items - private static ToolStripItem status; - private static ToolStripItem detailedStatusMenu; - private static ToolStripItem startMenu; - private static ToolStripItem stopMenu; - private static ToolStripItem deleteMenu; - private static ToolStripItem openWebConsoleMenu; - private static ToolStripItem copyOCLoginCommand; - private static ToolStripItem copyOCLoginForDeveloperMenu; - private static ToolStripItem copyOCLoginForKubeadminMenu; - private static ToolStripItem aboutMenu; - private static ToolStripItem exitMenu; - private static ToolStripItem settingsMenu; - - // Forms - private Form settingsWindow; - private Form about; - private Form statusForm; - - private Double pollInterval = 5000; // 5 seconds poll interval - - // Initialize tray - public TrayContext() - { - Bitmap bm = new Bitmap(Resource.ocp_logo); - notifyIcon = new NotifyIcon - { - Icon = Icon.FromHandle(bm.GetHicon()), - Visible = true, - ContextMenuStrip = SetContextMenu() - }; - notifyIcon.MouseClick += NotifyIcon_MouseClick; - - // start daemon - Task.Run(StartDaemon); - // Keep polling status and updating the statusMenuItem - var statusPollingTimer = new System.Timers.Timer(pollInterval); - statusPollingTimer.Enabled = true; - statusPollingTimer.Elapsed += pollStatusTimerEventHandler; - } - - private void NotifyIcon_MouseClick(object sender, MouseEventArgs e) - { - typeof(NotifyIcon).GetMethod("ShowContextMenu", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).Invoke(notifyIcon, null); - } - - // event handlers and methods - async static void PollStatus() - { - var status = await Task.Run(() => TaskHandlers.Status()); - if (status != null) - UpdateClusterStatusMenu(status); - } - - private static void pollStatusTimerEventHandler(object source, System.Timers.ElapsedEventArgs e) - { - Console.WriteLine("Elapsed event raise, polling status"); - PollStatus(); - } - - // populate the context menu for tray icon - private ContextMenuStrip SetContextMenu() - { - ContextMenuStrip cm = new ContextMenuStrip(); - - // Status Menu - status = cm.Items.Add(@"Unknown"); - status.Enabled = false; - - cm.Items.Add(new ToolStripSeparator()); - // Detailed status menu - detailedStatusMenu = cm.Items.Add(@"Status and Logs"); - detailedStatusMenu.Click += ShowDetailedStatusForm; - cm.Items.Add(new ToolStripSeparator()); - - // Start Menu - startMenu = cm.Items.Add(@"Start"); - startMenu.Click += StartMenu_Click; - - // Stop Menu - stopMenu = cm.Items.Add(@"Stop"); - stopMenu.Click += StopMenu_Click; - - // Delete Menu - deleteMenu = cm.Items.Add(@"Delete"); - deleteMenu.Click += DeleteMenu_Click; - - cm.Items.Add(new ToolStripSeparator()); - // Open web console menu - openWebConsoleMenu = cm.Items.Add(@"Launch Web Console"); - openWebConsoleMenu.Click += OpenWebConsoleMenu_Click; - - // Copy oc login command - copyOCLoginCommand = cm.Items.Add(@"Copy OC Login Command"); - - // Copy oc login command: developer - copyOCLoginForDeveloperMenu = (copyOCLoginCommand as ToolStripMenuItem).DropDownItems.Add(@"Developer"); - copyOCLoginForDeveloperMenu.Click += CopyOCLoginForDeveloperMenu_Click; - // Copy oc login command: kubeadmin - copyOCLoginForKubeadminMenu = (copyOCLoginCommand as ToolStripMenuItem).DropDownItems.Add(@"Kubeadmin"); - copyOCLoginForKubeadminMenu.Click += CopyOCLoginForKubeadminMenu_Click; - - cm.Items.Add(new ToolStripSeparator()); - // Settings menu - settingsMenu = cm.Items.Add(@"Settings"); - settingsMenu.Click += SettingsMenu_Click; - - cm.Items.Add(new ToolStripSeparator()); - // About menu - aboutMenu = cm.Items.Add(@"About"); - aboutMenu.Click += ShowAboutForm; - - // Exit menu - exitMenu = cm.Items.Add(@"Exit"); - exitMenu.Click += ExitMenu_Click; - - return cm; - } - - private void SettingsMenu_Click(object sender, EventArgs e) - { - if (settingsWindow == null) - settingsWindow = new CrcSettingsForm(); - - if (!settingsWindow.Visible) - settingsWindow.Show(); - settingsWindow.Focus(); - } - - async private void CopyOCLoginForKubeadminMenu_Click(object sender, EventArgs e) - { - var consoleResult = await Task.Run(() => TaskHandlers.LoginForKubeadmin()); - if (consoleResult != null) - { - if (consoleResult.Success) - Clipboard.SetText(string.Format("oc.exe login -u kubeadmin -p {0} {1}", consoleResult.ClusterConfig.KubeAdminPass, consoleResult.ClusterConfig.ClusterAPI)); - else - ShowNotification(@"Could not find credentials, is CRC runnning?", ToolTipIcon.Error); - } - } - - async private void CopyOCLoginForDeveloperMenu_Click(object sender, EventArgs e) - { - var consoleResult = await Task.Run(() => TaskHandlers.LoginForDeveloper()); - if (consoleResult != null) - { - if (consoleResult.Success) - Clipboard.SetText(string.Format("oc.exe login -u developer -p developer {0}", consoleResult.ClusterConfig.ClusterAPI)); - else - ShowNotification(@"Could not find credentials, is CRC running?", ToolTipIcon.Error); - } - } - - async private void OpenWebConsoleMenu_Click(object sender, EventArgs e) - { - var consoleResult = await Task.Run(() => TaskHandlers.WebConsole()); - if (consoleResult != null) - { - if (consoleResult.Success) - System.Diagnostics.Process.Start(consoleResult.ClusterConfig.WebConsoleURL); - else - ShowNotification(@"Could not open web console, is CRC running?", ToolTipIcon.Error); - } - } - - async private void DeleteMenu_Click(object sender, EventArgs e) - { - ShowNotification(@"Deleting Cluster", ToolTipIcon.Warning); - var deleteResult = await Task.Run(() => TaskHandlers.Delete()); - if (deleteResult != null) - { - if (deleteResult.Success) - DisplayMessageBox.Info(@"CodeReady Containers Cluster has been deleted", @"Cluster Deleted"); - else - DisplayMessageBox.Warn(@"Could not delete the cluster"); - } - } - - async private void StopMenu_Click(object sender, EventArgs e) - { - ShowNotification(@"Stopping Cluster", ToolTipIcon.Info); - var stopResult = await Task.Run(() => TaskHandlers.Stop()); - if (stopResult != null) - { - if (stopResult.Success) - DisplayMessageBox.Info(@"CodeReady Containers Cluster has stopped", @"Cluster Stopped"); - else - DisplayMessageBox.Warn(@"Cluster did not stop. Please check detailed status"); - } - } - - async private void StartMenu_Click(object sender, EventArgs e) - { - // Check using get-config if pullSecret is configured - var configs = TaskHandlers.ConfigView(); - if (configs.Configs.PullSecretFile == "") - { - var pullSecretForm = new PullSecretPickerForm(); - var pullSecretPath = pullSecretForm.ShowFilePicker(); - if (pullSecretPath == "") - { - DisplayMessageBox.Warn("No Pull Secret was provided, Cannot start cluster without pull secret."); - return; - } - Dictionary pullSecretConfig = new Dictionary - { - ["pull-secret-file"] = pullSecretPath - }; - TaskHandlers.SetConfig(pullSecretConfig); - } - - ShowNotification(@"Starting Cluster", ToolTipIcon.Info); - var startResult = await Task.Run(() => TaskHandlers.Start()); - if (startResult == null) - { - return; - } - if (startResult.KubeletStarted) - DisplayMessageBox.Info(@"CodeReady Containers Cluster has started", @"Cluster Started"); - else - DisplayMessageBox.Warn(@"Cluster did not start. Please check detailed status"); - } - - private void ExitMenu_Click(object sender, EventArgs e) - { - notifyIcon.Visible = false; - QuitApp(); - } - - private void ShowAboutForm(object sender, EventArgs e) - { - if (about == null) - about = new AboutForm(); - - if (!about.Visible) - about.Show(); - about.Focus(); - } - - private void ShowDetailedStatusForm(object sender, EventArgs e) - { - if (statusForm == null) - statusForm = new StatusForm(); - - if (!statusForm.Visible) - statusForm.Show(); - statusForm.Focus(); - } - - private static void UpdateClusterStatusMenu(StatusResult statusResult) - { - var text = ""; - if (!string.IsNullOrEmpty(statusResult.Error)) - { - text = ErrorText(statusResult); - } - else if (!string.IsNullOrEmpty(statusResult.CrcStatus)) - { - text = statusResult.CrcStatus; - } - else - { - text = @"Stopped"; - } - - // Until the user clicks on the menu the following Invoke method throws - // the below exception: - // - // Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll - // Invoke or BeginInvoke cannot be called on a control until the window handle has been created. - try - { - status.GetCurrentParent().Invoke((MethodInvoker) delegate - { - status.Text = text; - EnableMenuItems(); - }); - } - catch (InvalidOperationException) { } - } - - private static string ErrorText(StatusResult status) - { - if (status.Error.Length > 80) - { - return status.Error.Substring(0, Math.Min(80, status.Error.Length)) + " ..."; - } - return status.Error; - } - - private static void EnableMenuItems() - { - startMenu.Enabled = true; - deleteMenu.Enabled = true; - stopMenu.Enabled = true; - openWebConsoleMenu.Enabled = true; - copyOCLoginCommand.Enabled = true; - copyOCLoginForDeveloperMenu.Enabled = true; - copyOCLoginForKubeadminMenu.Enabled = true; - aboutMenu.Enabled = true; - detailedStatusMenu.Enabled = true; - } - - public void ShowNotification(string msg, ToolTipIcon toolTipIcon) - { - notifyIcon.BalloonTipIcon = toolTipIcon; - notifyIcon.BalloonTipText = msg; - notifyIcon.ShowBalloonTip(10); - } - private void StartDaemon() - { - var process = new Process(); - process.StartInfo.CreateNoWindow = true; - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardInput = true; - var currentExecutableLocation = typeof(Program).Assembly.Location; - var crcPath = Path.Combine(Path.GetDirectoryName(currentExecutableLocation), "crc.exe"); - process.StartInfo.FileName = crcPath; - - #if DEBUG - process.StartInfo.FileName = Path.Combine(Environment.GetEnvironmentVariable("GOPATH"), "bin", "crc.exe"); - #endif - process.StartInfo.Arguments = @"daemon --watchdog"; - process.StartInfo.WorkingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - Console.WriteLine(process.StartInfo.FileName); - try - { - process.Start(); - System.IO.StreamWriter daemonStdinWriter = process.StandardInput; - } - catch (Exception e) - { - DisplayMessageBox.Error(string.Format("Cannot start the daemon, Check the logs and restart the application, Error: {0}", e.Message)); - QuitApp(); - } - process.WaitForExit(); - if (process.ExitCode == 2) - { - DisplayMessageBox.Error("Setup incomplete, Open a terminal, run 'crc setup', and start again this application."); - } - else - { - DisplayMessageBox.Error("Daemon crashed, check the logs and restart the application"); - } - QuitApp(); - } - - private void QuitApp() - { - notifyIcon.Visible = false; - notifyIcon.Dispose(); - Environment.Exit(-1); - } - } -} - +} \ No newline at end of file diff --git a/crc-tray.csproj b/crc-tray.csproj index f7fbc82..1949f9b 100755 --- a/crc-tray.csproj +++ b/crc-tray.csproj @@ -76,8 +76,17 @@ false - - packages\Costura.Fody.5.3.0\lib\netstandard1.0\Costura.dll + + False + Libraries\HttpOverStream.dll + + + False + Libraries\HttpOverStream.Client.dll + + + False + Libraries\HttpOverStream.NamedPipe.dll packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll @@ -144,7 +153,7 @@ packages\System.Memory.4.5.4\lib\net461\System.Memory.dll - + packages\System.Net.Http.4.3.4\lib\net46\System.Net.Http.dll True True @@ -245,11 +254,10 @@ PullSecretPickerForm.cs + - - Form @@ -262,6 +270,7 @@ StatusForm.cs + @@ -269,6 +278,7 @@ True Resource.resx + AboutForm.cs