diff --git a/DesktopEdge/App.config b/DesktopEdge/App.config
index 1451e8e03..5ffd8f8ee 100644
--- a/DesktopEdge/App.config
+++ b/DesktopEdge/App.config
@@ -1,6 +1,6 @@
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/DesktopEdge/IdentityDetails.xaml.cs b/DesktopEdge/IdentityDetails.xaml.cs
index 68635e7d4..e18d255f3 100644
--- a/DesktopEdge/IdentityDetails.xaml.cs
+++ b/DesktopEdge/IdentityDetails.xaml.cs
@@ -1,166 +1,162 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using ZitiDesktopEdge.Models;
-
-namespace ZitiDesktopEdge {
- ///
- /// Interaction logic for IdentityDetails.xaml
- ///
- public partial class IdentityDetails:UserControl {
-
- private bool _isAttached = true;
- public delegate void Forgot(ZitiIdentity forgotten);
- public event Forgot OnForgot;
- public delegate void ErrorOccurred(string message);
- public event ErrorOccurred OnError;
- public delegate void Detched(MouseButtonEventArgs e);
- public event Detched OnDetach;
- public double MainHeight = 500;
-
- private List identities {
- get {
- return (List)Application.Current.Properties["Identities"];
- }
- }
-
- private ZitiIdentity _identity;
-
- public ZitiIdentity Identity {
- get {
- return _identity;
- }
- set {
- _identity = value;
- this.IdDetailToggle.Enabled = _identity.IsEnabled;
- UpdateView();
- IdentityArea.Opacity = 1.0;
- IdentityArea.Visibility = Visibility.Visible;
- this.Visibility = Visibility.Visible;
- }
- }
-
- public IdentityItem SelectedIdentity { get; set; }
-
- private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
- if (e.ChangedButton == MouseButton.Left) {
- _isAttached = false;
- OnDetach(e);
- }
- }
-
-
- public bool IsAttached {
- get {
- return _isAttached;
- }
- set {
- _isAttached = value;
- if (_isAttached) {
- Arrow.Visibility = Visibility.Visible;
- ConfirmArrow.Visibility = Visibility.Visible;
- } else {
- Arrow.Visibility = Visibility.Collapsed;
- ConfirmArrow.Visibility = Visibility.Collapsed;
- }
- }
- }
-
- public void UpdateView() {
- IdDetailName.Text = _identity.Name;
- IdDetailName.ToolTip = _identity.Name;
- IdDetailToggle.Enabled = _identity.IsEnabled;
- IdentityName.Value = _identity.Name;
- IdentityNetwork.Value = _identity.ControllerUrl;
- IdentityEnrollment.Value = _identity.Status;
- IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
- ServiceList.Children.Clear();
- if (_identity.Services.Count>0) {
- for (int i = 0; i < _identity.Services.Count; i++) {
- ServiceInfo editor = new ServiceInfo();
- editor.Label = _identity.Services[i].Name;
- editor.Value = _identity.Services[i].Url;
- editor.Warning = _identity.Services[i].Warning;
- editor.IsLocked = true;
- ServiceList.Children.Add(editor);
- }
- double newHeight = MainHeight - 300;
- ServiceRow.Height = new GridLength((double)newHeight);
- MainDetailScroll.MaxHeight = newHeight;
- MainDetailScroll.Height = newHeight;
- MainDetailScroll.Visibility = Visibility.Visible;
- ServiceTitle.Content = _identity.Services.Count + " SERVICES";
- } else {
- ServiceRow.Height = new GridLength((double)0.0);
- MainDetailScroll.Visibility = Visibility.Collapsed;
- ServiceTitle.Content = "NO SERVICES AVAILABLE";
- }
- }
-
- private void IdToggle(bool on) {
- ServiceClient.Client client = (ServiceClient.Client)Application.Current.Properties["ServiceClient"];
- client.IdentityOnOff(_identity.Fingerprint, on);
- SelectedIdentity.ToggleSwitch.Enabled = on;
- _identity.IsEnabled = on;
- IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
- }
-
- public IdentityDetails() {
- InitializeComponent();
- }
- private void HideMenu(object sender, MouseButtonEventArgs e) {
- this.Visibility = Visibility.Collapsed;
- }
-
- public void SetHeight(double height) {
- MainDetailScroll.Height = height;
- }
-
- private void ForgetIdentity(object sender, MouseButtonEventArgs e) {
- if (this.Visibility==Visibility.Visible) {
- ConfirmView.Visibility = Visibility.Visible;
- }
- }
-
- private void CancelConfirmButton_Click(object sender, RoutedEventArgs e) {
- ConfirmView.Visibility = Visibility.Collapsed;
- }
-
- private void ConfirmButton_Click(object sender, RoutedEventArgs e) {
- this.Visibility = Visibility.Collapsed;
- ServiceClient.Client client = (ServiceClient.Client)Application.Current.Properties["ServiceClient"];
- try {
- client.RemoveIdentity(_identity.Fingerprint);
-
- ZitiIdentity forgotten = new ZitiIdentity();
- foreach (var id in identities) {
- if (id.Fingerprint == _identity.Fingerprint) {
- forgotten = id;
- identities.Remove(id);
- break;
- }
- }
-
- if (OnForgot != null) {
- OnForgot(forgotten);
- }
- } catch (ServiceClient.ServiceException se) {
- OnError(se.Message);
- } catch (Exception ex) {
- OnError(ex.Message);
- }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using ZitiDesktopEdge.Models;
+using ZitiDesktopEdge.ServiceClient;
+
+using NLog;
+
+namespace ZitiDesktopEdge {
+ ///
+ /// Interaction logic for IdentityDetails.xaml
+ ///
+ public partial class IdentityDetails:UserControl {
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+ private bool _isAttached = true;
+ public delegate void Forgot(ZitiIdentity forgotten);
+ public event Forgot OnForgot;
+ public delegate void ErrorOccurred(string message);
+ public event ErrorOccurred OnError;
+ public delegate void Detched(MouseButtonEventArgs e);
+ public event Detched OnDetach;
+ public double MainHeight = 500;
+
+ private List identities {
+ get {
+ return (List)Application.Current.Properties["Identities"];
+ }
+ }
+
+ private ZitiIdentity _identity;
+
+ public ZitiIdentity Identity {
+ get {
+ return _identity;
+ }
+ set {
+ _identity = value;
+ this.IdDetailToggle.Enabled = _identity.IsEnabled;
+ UpdateView();
+ IdentityArea.Opacity = 1.0;
+ IdentityArea.Visibility = Visibility.Visible;
+ this.Visibility = Visibility.Visible;
+ }
+ }
+
+ public IdentityItem SelectedIdentity { get; set; }
+
+ private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
+ if (e.ChangedButton == MouseButton.Left) {
+ _isAttached = false;
+ OnDetach(e);
+ }
+ }
+
+
+ public bool IsAttached {
+ get {
+ return _isAttached;
+ }
+ set {
+ _isAttached = value;
+ if (_isAttached) {
+ Arrow.Visibility = Visibility.Visible;
+ ConfirmArrow.Visibility = Visibility.Visible;
+ } else {
+ Arrow.Visibility = Visibility.Collapsed;
+ ConfirmArrow.Visibility = Visibility.Collapsed;
+ }
+ }
+ }
+
+ public void UpdateView() {
+ IdDetailName.Text = _identity.Name;
+ IdDetailName.ToolTip = _identity.Name;
+ IdDetailToggle.Enabled = _identity.IsEnabled;
+ IdentityName.Value = _identity.Name;
+ IdentityNetwork.Value = _identity.ControllerUrl;
+ IdentityEnrollment.Value = _identity.Status;
+ IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
+ ServiceList.Children.Clear();
+ if (_identity.Services.Count>0) {
+ foreach(var zitiSvc in _identity.Services.OrderBy(s => s.Name.ToLower())) {
+ Logger.Debug("painting: " + zitiSvc.Name);
+ ServiceInfo editor = new ServiceInfo();
+ editor.Label = zitiSvc.Name;
+ editor.Value = zitiSvc.Url;
+ editor.Warning = zitiSvc.Warning;
+ editor.IsLocked = true;
+ ServiceList.Children.Add(editor);
+ }
+ double newHeight = MainHeight - 300;
+ ServiceRow.Height = new GridLength((double)newHeight);
+ MainDetailScroll.MaxHeight = newHeight;
+ MainDetailScroll.Height = newHeight;
+ MainDetailScroll.Visibility = Visibility.Visible;
+ ServiceTitle.Content = _identity.Services.Count + " SERVICES";
+ } else {
+ ServiceRow.Height = new GridLength((double)0.0);
+ MainDetailScroll.Visibility = Visibility.Collapsed;
+ ServiceTitle.Content = "NO SERVICES AVAILABLE";
+ }
+ }
+
+ async private void IdToggle(bool on) {
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ await client.IdentityOnOffAsync(_identity.Fingerprint, on);
+ SelectedIdentity.ToggleSwitch.Enabled = on;
+ _identity.IsEnabled = on;
+ IdentityStatus.Value = _identity.IsEnabled ? "active" : "disabled";
+ }
+
+ public IdentityDetails() {
+ InitializeComponent();
+ }
+ private void HideMenu(object sender, MouseButtonEventArgs e) {
+ this.Visibility = Visibility.Collapsed;
+ }
+
+ public void SetHeight(double height) {
+ MainDetailScroll.Height = height;
+ }
+
+ private void ForgetIdentity(object sender, MouseButtonEventArgs e) {
+ if (this.Visibility==Visibility.Visible) {
+ ConfirmView.Visibility = Visibility.Visible;
+ }
+ }
+
+ private void CancelConfirmButton_Click(object sender, RoutedEventArgs e) {
+ ConfirmView.Visibility = Visibility.Collapsed;
+ }
+
+ async private void ConfirmButton_Click(object sender, RoutedEventArgs e) {
+ this.Visibility = Visibility.Collapsed;
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ try {
+ await client.RemoveIdentityAsync(_identity.Fingerprint);
+
+ ZitiIdentity forgotten = new ZitiIdentity();
+ foreach (var id in identities) {
+ if (id.Fingerprint == _identity.Fingerprint) {
+ forgotten = id;
+ identities.Remove(id);
+ break;
+ }
+ }
+
+ if (OnForgot != null) {
+ OnForgot(forgotten);
+ }
+ } catch (DataStructures.ServiceException se) {
+ OnError(se.Message);
+ } catch (Exception ex) {
+ OnError(ex.Message);
+ }
+ }
+ }
+}
diff --git a/DesktopEdge/MainMenu.xaml.cs b/DesktopEdge/MainMenu.xaml.cs
index 678c29e00..e9ebbd83e 100644
--- a/DesktopEdge/MainMenu.xaml.cs
+++ b/DesktopEdge/MainMenu.xaml.cs
@@ -1,323 +1,328 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Diagnostics;
-using System;
-using System.Threading;
-using System.Management.Automation;
-using ZitiDesktopEdge.Models;
-using System.Reflection;
-using System.Web;
-using System.Net.Mail;
-using System.IO;
-using System.Net;
-using Newtonsoft.Json.Linq;
-using System.Threading.Tasks;
-
-namespace ZitiDesktopEdge
-{
- ///
- /// Interaction logic for MainMenu.xaml
- ///
- public partial class MainMenu : UserControl {
-
-
- public delegate void AttachementChanged(bool attached);
- public event AttachementChanged OnAttachmentChange;
- public delegate void LogLevelChanged(string level);
- public event LogLevelChanged OnLogLevelChanged;
- public delegate void Detched(MouseButtonEventArgs e);
- public event Detched OnDetach;
- public string menuState = "Main";
- public string licenseData = "it's open source.";
- public string LogLevel = "";
- private string _updateUrl = "https://api.github.com/repos/openziti/desktop-edge-win/releases/latest";
- private string _downloadUrl = "";
-
- public MainMenu() {
- InitializeComponent();
- LicensesItems.Text = licenseData;
- CheckUpdates();
- }
-
- private void HideMenu(object sender, MouseButtonEventArgs e) {
- menuState = "Menu";
- UpdateState();
- MainMenuArea.Visibility = Visibility.Collapsed;
- }
- private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
- if (e.ChangedButton == MouseButton.Left) {
- OnDetach(e);
- }
- }
-
- private void CloseApp(object sender, MouseButtonEventArgs e) {
- Application.Current.Shutdown();
- }
-
- private void DoUpdate(object sender, MouseButtonEventArgs e) {
- System.Diagnostics.Process.Start(_downloadUrl);
- }
-
- private void ShowAbout(object sender, MouseButtonEventArgs e) {
- menuState = "About";
- UpdateState();
- }
-
- private void ShowAdvanced(object sender, MouseButtonEventArgs e) {
- menuState = "Advanced";
- UpdateState();
- }
- private void ShowLicenses(object sender, MouseButtonEventArgs e) {
- menuState = "Licenses";
- UpdateState();
- }
- private void ShowConfig(object sender, MouseButtonEventArgs e) {
- menuState = "Config";
- UpdateState();
- }
- private void ShowLogs(object sender, MouseButtonEventArgs e) {
- menuState = "Logs";
- UpdateState();
- }
- private void ShowUILogs(object sender, MouseButtonEventArgs e) {
- menuState = "UILogs";
- UpdateState();
- }
- private void SetLogLevel(object sender, MouseButtonEventArgs e) {
- menuState = "LogLevel";
- UpdateState();
- }
-
- private void CheckUpdates() {
- try
- {
- HttpWebRequest httpWebRequest = WebRequest.CreateHttp(_updateUrl);
- httpWebRequest.Method = "GET";
- httpWebRequest.ContentType = "application/json";
- httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
- HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
- StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream());
- string result = streamReader.ReadToEnd();
- JObject json = JObject.Parse(result);
- string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
- string serverVersion = json.Property("tag_name").Value.ToString() + ".0";
-
- Version installed = new Version(currentVersion);
- Version published = new Version(serverVersion);
- int compare = installed.CompareTo(published);
- if (compare < 0)
- {
- UpdateAvailable.Content = "An Upgrade is available, click to download";
- UpdateAvailable.Visibility = Visibility.Visible;
- }
- else if (compare > 0)
- {
- UpdateAvailable.Content = "Your version is newer than the released version";
- UpdateAvailable.Visibility = Visibility.Visible;
- }
- JArray assets = JArray.Parse(json.Property("assets").Value.ToString());
- foreach (JObject asset in assets.Children())
- {
- _downloadUrl = asset.Property("browser_download_url").Value.ToString();
- break;
- }
- } catch(Exception ex)
- {
- UpdateAvailable.Content = "An exception occurred while performing upgrade check";
- Debug.WriteLine("Error when checking for version: " + ex.Message);
- UpdateAvailable.Visibility = Visibility.Visible;
- }
- }
-
- private void UpdateState() {
- MainItems.Visibility = Visibility.Collapsed;
- AboutItems.Visibility = Visibility.Collapsed;
- MainItemsButton.Visibility = Visibility.Collapsed;
- AboutItemsArea.Visibility = Visibility.Collapsed;
- BackArrow.Visibility = Visibility.Collapsed;
- AdvancedItems.Visibility = Visibility.Collapsed;
- LicensesItems.Visibility = Visibility.Collapsed;
- LogsItems.Visibility = Visibility.Collapsed;
- ConfigItems.Visibility = Visibility.Collapsed;
- LogLevelItems.Visibility = Visibility.Collapsed;
-
- if (menuState == "About") {
- MenuTitle.Content = "About";
- AboutItemsArea.Visibility = Visibility.Visible;
- AboutItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
-
- string version = "";
- try {
- ServiceClient.TunnelStatus s = (ServiceClient.TunnelStatus)Application.Current.Properties["CurrentTunnelStatus"];
- version = $"{s.ServiceVersion.Version}@{s.ServiceVersion.Revision}";
- } catch (Exception e) {
-#if DEBUG
- Debug.WriteLine(e.ToString());
-#endif
- }
-
- // Interface Version
- VersionInfo.Content = "App: " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()+" Service: "+ version;
-
- } else if (menuState=="Advanced") {
- MenuTitle.Content = "Advanced Settings";
- AdvancedItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState=="Licenses") {
- MenuTitle.Content = "Third Party Licenses";
- LicensesItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState=="Logs") {
- ServiceClient.Client client = (ServiceClient.Client)Application.Current.Properties["ServiceClient"];
- MenuTitle.Content = "Service Logs";
- LogsItems.Text = client.GetLogs();
- LogsItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "UILogs") {
- MenuTitle.Content = "Application Logs";
- LogsItems.Text = UILog.GetLogs();
- LogsItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState == "LogLevel") {
- ResetLevels();
-
- MenuTitle.Content = "Set Log Level";
- LogLevelItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
- } else if (menuState=="Config") {
- MenuTitle.Content = "Tunnel Configuration";
- ConfigItems.Visibility = Visibility.Visible;
- BackArrow.Visibility = Visibility.Visible;
-
- ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
- ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
- ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
- ConfigDns.Value = Application.Current.Properties["dns"]?.ToString();
- } else {
- MenuTitle.Content = "Main Menu";
- MainItems.Visibility = Visibility.Visible;
- MainItemsButton.Visibility = Visibility.Visible;
- }
- }
-
- private void GoBack(object sender, MouseButtonEventArgs e) {
- if (menuState=="Config"||menuState=="Logs"||menuState=="UILogs") {
- menuState = "Advanced";
- } else if (menuState=="Licenses") {
- menuState = "About";
- } else {
- menuState = "Menu";
- }
- UpdateState();
- }
- private void ShowPrivacy(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://netfoundry.io/privacy") { UseShellExecute = true });
- }
- private void ShowTerms(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://netfoundry.io/terms") { UseShellExecute = true });
- }
- private void ShowFeedback(object sender, MouseButtonEventArgs e) {
- ServiceClient.Client client = (ServiceClient.Client)Application.Current.Properties["ServiceClient"];
- var mailMessage = new MailMessage();
- mailMessage.From = new MailAddress("ziti-support@netfoundry.io");
- mailMessage.Subject = "Ziti Support";
- mailMessage.IsBodyHtml = true;
- mailMessage.Body = "";
-
- string timestamp = DateTime.Now.ToFileTime().ToString();
- string serviceLogTempFile = Path.Combine(Path.GetTempPath(), timestamp+"-Ziti-Service.log");
- using (StreamWriter sw = new StreamWriter(serviceLogTempFile)) {
- sw.WriteLine(client.GetLogs());
- }
-
- string uiLogTempFile = Path.Combine(Path.GetTempPath(), timestamp+"-Ziti-Application.log");
- using (StreamWriter sw = new StreamWriter(uiLogTempFile)) {
- sw.WriteLine(UILog.GetLogs());
- }
-
- mailMessage.Attachments.Add(new Attachment(serviceLogTempFile));
- mailMessage.Attachments.Add(new Attachment(uiLogTempFile));
-
- string emlFile = Path.Combine(Path.GetTempPath(), timestamp+"-ziti.eml");
-
- using (var filestream = File.Open(emlFile, FileMode.Create)) {
- var binaryWriter = new BinaryWriter(filestream);
- binaryWriter.Write(System.Text.Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
- var assembly = typeof(SmtpClient).Assembly;
- var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
- var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
- var mailWriter = mailWriterContructor.Invoke(new object[] { filestream });
- var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
- sendMethod.Invoke(mailMessage, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { mailWriter, true, true }, null);
- var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
- closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
- }
-
- Process.Start(emlFile);
-
-
-
- //string body = HttpUtility.UrlEncode("\n\nService Logs\n\n" + client.GetLogs());// + "\n\nApplication Logs\n\n" + UILog.GetLogs());
- //Process.Start(new ProcessStartInfo("mailto:ziti-support@netfoundry.io?subject=Ziti%20Support&body="+body) { UseShellExecute = true });
- }
- private void ShowSupport(object sender, MouseButtonEventArgs e) {
- Process.Start(new ProcessStartInfo("https://openziti.discourse.group/") { UseShellExecute = true });
- }
-
- private void DetachWindow(object sender, MouseButtonEventArgs e) {
- Application.Current.MainWindow.ShowInTaskbar = true;
- DetachButton.Visibility = Visibility.Collapsed;
- AttachButton.Visibility = Visibility.Visible;
- Arrow.Visibility = Visibility.Collapsed;
- if (OnAttachmentChange != null) {
- OnAttachmentChange(false);
- }
- MainMenuArea.Visibility = Visibility.Collapsed;
- }
-
- public void Detach() {
- Application.Current.MainWindow.ShowInTaskbar = true;
- DetachButton.Visibility = Visibility.Collapsed;
- AttachButton.Visibility = Visibility.Visible;
- Arrow.Visibility = Visibility.Collapsed;
- }
- private void RetachWindow(object sender, MouseButtonEventArgs e) {
- Application.Current.MainWindow.ShowInTaskbar = false;
- DetachButton.Visibility = Visibility.Visible;
- AttachButton.Visibility = Visibility.Collapsed;
- Arrow.Visibility = Visibility.Visible;
- if (OnAttachmentChange != null) {
- OnAttachmentChange(true);
- }
- }
-
- private void ResetLevels() {
- if (this.LogLevel == "") this.LogLevel = "error";
- LogVerbose.IsSelected = false;
- LogDebug.IsSelected = false;
- LogInfo.IsSelected = false;
- LogError.IsSelected = false;
- LogFatal.IsSelected = false;
- LogWarn.IsSelected = false;
- LogTrace.IsSelected = false;
- if (this.LogLevel == "verbose") LogVerbose.IsSelected = true;
- else if (this.LogLevel == "debug") LogDebug.IsSelected = true;
- else if (this.LogLevel == "info") LogInfo.IsSelected = true;
- else if (this.LogLevel == "error") LogError.IsSelected = true;
- else if (this.LogLevel == "fatal") LogFatal.IsSelected = true;
- else if (this.LogLevel == "warn") LogWarn.IsSelected = true;
- else if (this.LogLevel == "trace") LogTrace.IsSelected = true;
- }
-
- private void SetLevel(object sender, MouseButtonEventArgs e) {
- SubOptionItem item = (SubOptionItem)sender;
- this.LogLevel = item.Label.ToLower();
- if (OnLogLevelChanged != null) {
- OnLogLevelChanged(this.LogLevel);
- }
- ResetLevels();
- }
- }
-}
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Diagnostics;
+using System;
+using System.Threading;
+using ZitiDesktopEdge.Models;
+using System.Reflection;
+using System.Web;
+using System.Net.Mail;
+using System.IO;
+using System.Net;
+using Newtonsoft.Json.Linq;
+using ZitiDesktopEdge.ServiceClient;
+
+using NLog;
+using NLog.Config;
+using NLog.Targets;
+
+using ZitiDesktopEdge.Server;
+
+namespace ZitiDesktopEdge
+{
+ ///
+ /// Interaction logic for MainMenu.xaml
+ ///
+ public partial class MainMenu : UserControl {
+
+
+ public delegate void AttachementChanged(bool attached);
+ public event AttachementChanged OnAttachmentChange;
+ public delegate void LogLevelChanged(string level);
+ public event LogLevelChanged OnLogLevelChanged;
+ public delegate void Detched(MouseButtonEventArgs e);
+ public event Detched OnDetach;
+ public string menuState = "Main";
+ public string licenseData = "it's open source.";
+ public string LogLevel = "";
+ private string _updateUrl = "https://api.github.com/repos/openziti/desktop-edge-win/releases/latest";
+ private string _downloadUrl = "";
+
+ public MainMenu() {
+ InitializeComponent();
+ LicensesItems.Text = licenseData;
+ CheckUpdates();
+ }
+
+ private void HideMenu(object sender, MouseButtonEventArgs e) {
+ menuState = "Menu";
+ UpdateState();
+ MainMenuArea.Visibility = Visibility.Collapsed;
+ }
+ private void Window_MouseDown(object sender, MouseButtonEventArgs e) {
+ if (e.ChangedButton == MouseButton.Left) {
+ OnDetach(e);
+ }
+ }
+
+ private void CloseApp(object sender, MouseButtonEventArgs e) {
+ Application.Current.Shutdown();
+ }
+
+ private void DoUpdate(object sender, MouseButtonEventArgs e) {
+ System.Diagnostics.Process.Start(_downloadUrl);
+ }
+
+ private void ShowAbout(object sender, MouseButtonEventArgs e) {
+ menuState = "About";
+ UpdateState();
+ }
+
+ private void ShowAdvanced(object sender, MouseButtonEventArgs e) {
+ menuState = "Advanced";
+ UpdateState();
+ }
+ private void ShowLicenses(object sender, MouseButtonEventArgs e) {
+ menuState = "Licenses";
+ UpdateState();
+ }
+ private void ShowConfig(object sender, MouseButtonEventArgs e) {
+ menuState = "Config";
+ UpdateState();
+ }
+ private void ShowLogs(object sender, MouseButtonEventArgs e) {
+ menuState = "Logs";
+ UpdateState();
+ }
+ private void ShowUILogs(object sender, MouseButtonEventArgs e) {
+ menuState = "UILogs";
+ UpdateState();
+ }
+ private void SetLogLevel(object sender, MouseButtonEventArgs e) {
+ menuState = "LogLevel";
+ UpdateState();
+ }
+
+ private void CheckUpdates() {
+ try
+ {
+ HttpWebRequest httpWebRequest = WebRequest.CreateHttp(_updateUrl);
+ httpWebRequest.Method = "GET";
+ httpWebRequest.ContentType = "application/json";
+ httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36";
+ HttpWebResponse httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
+ StreamReader streamReader = new StreamReader(httpResponse.GetResponseStream());
+ string result = streamReader.ReadToEnd();
+ JObject json = JObject.Parse(result);
+ string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
+ string serverVersion = json.Property("tag_name").Value.ToString() + ".0";
+
+ Version installed = new Version(currentVersion);
+ Version published = new Version(serverVersion);
+ int compare = installed.CompareTo(published);
+ if (compare < 0)
+ {
+ UpdateAvailable.Content = "An Upgrade is available, click to download";
+ UpdateAvailable.Visibility = Visibility.Visible;
+ }
+ else if (compare > 0)
+ {
+ UpdateAvailable.Content = "Your version is newer than the released version";
+ UpdateAvailable.Visibility = Visibility.Visible;
+ }
+ JArray assets = JArray.Parse(json.Property("assets").Value.ToString());
+ foreach (JObject asset in assets.Children())
+ {
+ _downloadUrl = asset.Property("browser_download_url").Value.ToString();
+ break;
+ }
+ } catch(Exception ex)
+ {
+ UpdateAvailable.Content = "An exception occurred while performing upgrade check";
+ Debug.WriteLine("Error when checking for version: " + ex.Message);
+ UpdateAvailable.Visibility = Visibility.Visible;
+ }
+ }
+
+ private void UpdateState() {
+ MainItems.Visibility = Visibility.Collapsed;
+ AboutItems.Visibility = Visibility.Collapsed;
+ MainItemsButton.Visibility = Visibility.Collapsed;
+ AboutItemsArea.Visibility = Visibility.Collapsed;
+ BackArrow.Visibility = Visibility.Collapsed;
+ AdvancedItems.Visibility = Visibility.Collapsed;
+ LicensesItems.Visibility = Visibility.Collapsed;
+ LogsItems.Visibility = Visibility.Collapsed;
+ ConfigItems.Visibility = Visibility.Collapsed;
+ LogLevelItems.Visibility = Visibility.Collapsed;
+
+ if (menuState == "About") {
+ MenuTitle.Content = "About";
+ AboutItemsArea.Visibility = Visibility.Visible;
+ AboutItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+
+ string version = "";
+ try {
+ DataStructures.TunnelStatus s = (DataStructures.TunnelStatus)Application.Current.Properties["CurrentTunnelStatus"];
+ version = $"{s.ServiceVersion.Version}@{s.ServiceVersion.Revision}";
+ } catch (Exception e) {
+#if DEBUG
+ Debug.WriteLine(e.ToString());
+#endif
+ }
+
+ // Interface Version
+ VersionInfo.Content = "App: " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()+" Service: "+ version;
+
+ } else if (menuState=="Advanced") {
+ MenuTitle.Content = "Advanced Settings";
+ AdvancedItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState=="Licenses") {
+ MenuTitle.Content = "Third Party Licenses";
+ LicensesItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState=="Logs") {
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ MenuTitle.Content = "Service Logs";
+ LogsItems.Text = client.GetLogs();
+ LogsItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "UILogs") {
+ MenuTitle.Content = "Application Logs";
+ LogsItems.Text = UILog.GetLogs();
+ LogsItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState == "LogLevel") {
+ ResetLevels();
+
+ MenuTitle.Content = "Set Log Level";
+ LogLevelItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+ } else if (menuState=="Config") {
+ MenuTitle.Content = "Tunnel Configuration";
+ ConfigItems.Visibility = Visibility.Visible;
+ BackArrow.Visibility = Visibility.Visible;
+
+ ConfigIp.Value = Application.Current.Properties["ip"]?.ToString();
+ ConfigSubnet.Value = Application.Current.Properties["subnet"]?.ToString();
+ ConfigMtu.Value = Application.Current.Properties["mtu"]?.ToString();
+ ConfigDns.Value = Application.Current.Properties["dns"]?.ToString();
+ } else {
+ MenuTitle.Content = "Main Menu";
+ MainItems.Visibility = Visibility.Visible;
+ MainItemsButton.Visibility = Visibility.Visible;
+ }
+ }
+
+ private void GoBack(object sender, MouseButtonEventArgs e) {
+ if (menuState=="Config"||menuState=="Logs"||menuState=="UILogs") {
+ menuState = "Advanced";
+ } else if (menuState=="Licenses") {
+ menuState = "About";
+ } else {
+ menuState = "Menu";
+ }
+ UpdateState();
+ }
+ private void ShowPrivacy(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://netfoundry.io/privacy") { UseShellExecute = true });
+ }
+ private void ShowTerms(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://netfoundry.io/terms") { UseShellExecute = true });
+ }
+ private void ShowFeedback(object sender, MouseButtonEventArgs e) {
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ var mailMessage = new MailMessage();
+ mailMessage.From = new MailAddress("ziti-support@netfoundry.io");
+ mailMessage.Subject = "Ziti Support";
+ mailMessage.IsBodyHtml = true;
+ mailMessage.Body = "";
+
+ string timestamp = DateTime.Now.ToFileTime().ToString();
+ string serviceLogTempFile = Path.Combine(Path.GetTempPath(), timestamp+"-Ziti-Service.log");
+ using (StreamWriter sw = new StreamWriter(serviceLogTempFile)) {
+ sw.WriteLine(client.GetLogs());
+ }
+
+ string uiLogTempFile = Path.Combine(Path.GetTempPath(), timestamp+"-Ziti-Application.log");
+ using (StreamWriter sw = new StreamWriter(uiLogTempFile)) {
+ sw.WriteLine(UILog.GetLogs());
+ }
+
+ mailMessage.Attachments.Add(new Attachment(serviceLogTempFile));
+ mailMessage.Attachments.Add(new Attachment(uiLogTempFile));
+
+ string emlFile = Path.Combine(Path.GetTempPath(), timestamp+"-ziti.eml");
+
+ using (var filestream = File.Open(emlFile, FileMode.Create)) {
+ var binaryWriter = new BinaryWriter(filestream);
+ binaryWriter.Write(System.Text.Encoding.UTF8.GetBytes("X-Unsent: 1" + Environment.NewLine));
+ var assembly = typeof(SmtpClient).Assembly;
+ var mailWriterType = assembly.GetType("System.Net.Mail.MailWriter");
+ var mailWriterContructor = mailWriterType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new[] { typeof(Stream) }, null);
+ var mailWriter = mailWriterContructor.Invoke(new object[] { filestream });
+ var sendMethod = typeof(MailMessage).GetMethod("Send", BindingFlags.Instance | BindingFlags.NonPublic);
+ sendMethod.Invoke(mailMessage, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { mailWriter, true, true }, null);
+ var closeMethod = mailWriter.GetType().GetMethod("Close", BindingFlags.Instance | BindingFlags.NonPublic);
+ closeMethod.Invoke(mailWriter, BindingFlags.Instance | BindingFlags.NonPublic, null, new object[] { }, null);
+ }
+
+ Process.Start(emlFile);
+
+
+
+ //string body = HttpUtility.UrlEncode("\n\nService Logs\n\n" + client.GetLogs());// + "\n\nApplication Logs\n\n" + UILog.GetLogs());
+ //Process.Start(new ProcessStartInfo("mailto:ziti-support@netfoundry.io?subject=Ziti%20Support&body="+body) { UseShellExecute = true });
+ }
+ private void ShowSupport(object sender, MouseButtonEventArgs e) {
+ Process.Start(new ProcessStartInfo("https://openziti.discourse.group/") { UseShellExecute = true });
+ }
+
+ private void DetachWindow(object sender, MouseButtonEventArgs e) {
+ Application.Current.MainWindow.ShowInTaskbar = true;
+ DetachButton.Visibility = Visibility.Collapsed;
+ AttachButton.Visibility = Visibility.Visible;
+ Arrow.Visibility = Visibility.Collapsed;
+ if (OnAttachmentChange != null) {
+ OnAttachmentChange(false);
+ }
+ MainMenuArea.Visibility = Visibility.Collapsed;
+ }
+
+ public void Detach() {
+ Application.Current.MainWindow.ShowInTaskbar = true;
+ DetachButton.Visibility = Visibility.Collapsed;
+ AttachButton.Visibility = Visibility.Visible;
+ Arrow.Visibility = Visibility.Collapsed;
+ }
+ private void RetachWindow(object sender, MouseButtonEventArgs e) {
+ Application.Current.MainWindow.ShowInTaskbar = false;
+ DetachButton.Visibility = Visibility.Visible;
+ AttachButton.Visibility = Visibility.Collapsed;
+ Arrow.Visibility = Visibility.Visible;
+ if (OnAttachmentChange != null) {
+ OnAttachmentChange(true);
+ }
+ }
+
+ private void ResetLevels() {
+ if (this.LogLevel == "") this.LogLevel = "error";
+ LogVerbose.IsSelected = false;
+ LogDebug.IsSelected = false;
+ LogInfo.IsSelected = false;
+ LogError.IsSelected = false;
+ LogFatal.IsSelected = false;
+ LogWarn.IsSelected = false;
+ LogTrace.IsSelected = false;
+ if (this.LogLevel == "verbose") LogVerbose.IsSelected = true;
+ else if (this.LogLevel == "debug") LogDebug.IsSelected = true;
+ else if (this.LogLevel == "info") LogInfo.IsSelected = true;
+ else if (this.LogLevel == "error") LogError.IsSelected = true;
+ else if (this.LogLevel == "fatal") LogFatal.IsSelected = true;
+ else if (this.LogLevel == "warn") LogWarn.IsSelected = true;
+ else if (this.LogLevel == "trace") LogTrace.IsSelected = true;
+ }
+
+ private void SetLevel(object sender, MouseButtonEventArgs e) {
+ SubOptionItem item = (SubOptionItem)sender;
+ this.LogLevel = item.Label.ToLower();
+ if (OnLogLevelChanged != null) {
+ OnLogLevelChanged(this.LogLevel);
+ }
+ ResetLevels();
+ }
+ }
+}
diff --git a/DesktopEdge/MainWindow.xaml b/DesktopEdge/MainWindow.xaml
index 42c7e442e..8225e8575 100644
--- a/DesktopEdge/MainWindow.xaml
+++ b/DesktopEdge/MainWindow.xaml
@@ -1,323 +1,323 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DesktopEdge/MainWindow.xaml.cs b/DesktopEdge/MainWindow.xaml.cs
index 07387ee49..a87807ab9 100644
--- a/DesktopEdge/MainWindow.xaml.cs
+++ b/DesktopEdge/MainWindow.xaml.cs
@@ -3,27 +3,36 @@
using System.Windows;
using System.Windows.Input;
using System.IO;
-using ZitiDesktopEdge.Models;
-using ZitiDesktopEdge.ServiceClient;
using System.ServiceProcess;
using System.Linq;
using System.Diagnostics;
using System.Windows.Controls;
using System.Drawing;
+using System.Threading;
+using System.Threading.Tasks;
+
+using ZitiDesktopEdge.Models;
+using ZitiDesktopEdge.DataStructures;
+using ZitiDesktopEdge.ServiceClient;
+using NLog;
+using NLog.Config;
+using NLog.Targets;
namespace ZitiDesktopEdge {
///
/// Interaction logic for MainWindow.xaml
///
- public partial class MainWindow:Window {
+ public partial class MainWindow : Window {
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public System.Windows.Forms.NotifyIcon notifyIcon;
public string Position = "Bottom";
private DateTime _startDate;
- private System.Windows.Forms.Timer _timer;
- private Client serviceClient = null;
+ private System.Windows.Forms.Timer _tunnelUptimeTimer;
+ private DataClient serviceClient = null;
+ MonitorClient monitorClient = null;
private bool _isAttached = true;
private bool _isServiceInError = false;
private int _right = 75;
@@ -32,32 +41,47 @@ public partial class MainWindow:Window {
private double _maxHeight = 800d;
private string[] suffixes = { "Bps", "kBps", "mBps", "gBps", "tBps", "pBps" };
+ private static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
+
private List identities {
get {
return (List)Application.Current.Properties["Identities"];
}
}
- private void LaunchOrInstall() {
- ServiceController ctl = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName=="ziti");
- if (ctl==null) {
- SetCantDisplay();
- } else {
- if (ctl.Status!=ServiceControllerStatus.Running) {
- try {
- ctl.Start();
- } catch (Exception e) {
- UILog.Log(e.Message);
- SetCantDisplay();
- }
- }
- }
- }
-
- private List services = new List();
public MainWindow() {
InitializeComponent();
+ var asm = System.Reflection.Assembly.GetExecutingAssembly();
+ var logname = asm.GetName().Name;
+
+ var curdir = Path.GetDirectoryName(asm.Location);
+ string nlogFile = Path.Combine(curdir, logname + ".log.config");
+
+ if (File.Exists(nlogFile)) {
+ LogManager.Configuration = new XmlLoggingConfiguration(nlogFile);
+ } else {
+ var config = new LoggingConfiguration();
+ // Targets where to log to: File and Console
+ var logfile = new FileTarget("logfile") {
+ FileName = $"logs\\UI\\{logname}.log",
+ ArchiveEvery = FileArchivePeriod.Day,
+ ArchiveNumbering = ArchiveNumberingMode.Rolling,
+ MaxArchiveFiles = 7,
+ Layout = "${longdate}|${level:uppercase=true:padding=5}|${logger}|${message}",
+ //ArchiveAboveSize = 10000,
+ };
+ var logconsole = new ConsoleTarget("logconsole");
+
+ // Rules for mapping loggers to targets
+ config.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole);
+ config.AddRule(LogLevel.Debug, LogLevel.Fatal, logfile);
+
+ // Apply config
+ LogManager.Configuration = config;
+ }
+ Logger.Info("service started - logger initialized");
+
App.Current.MainWindow.WindowState = WindowState.Normal;
App.Current.MainWindow.Closing += MainWindow_Closing;
App.Current.MainWindow.Deactivated += MainWindow_Deactivated;
@@ -69,8 +93,6 @@ public MainWindow() {
IdentityMenu.OnDetach += OnDetach;
MainMenu.OnDetach += OnDetach;
- LaunchOrInstall();
-
SetNotifyIcon("white");
}
@@ -105,24 +127,33 @@ private void MainWindow_Deactivated(object sender, EventArgs e) {
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
notifyIcon.Visible = false;
- notifyIcon.Icon.Dispose();
- notifyIcon.Dispose();
+ //notifyIcon.Icon.Dispose();
+ //notifyIcon.Dispose();
}
-
- private void SetCantDisplay(string msg, string detailMessage) {
+
+ private void SetCantDisplay(string title, string detailMessage, Visibility closeButtonVisibility) {
NoServiceView.Visibility = Visibility.Visible;
- ErrorMsg.Content = msg;
+ CloseErrorButton.IsEnabled = true;
+ CloseErrorButton.Visibility = closeButtonVisibility;
+ ErrorMsg.Content = title;
ErrorMsgDetail.Content = detailMessage;
SetNotifyIcon("red");
_isServiceInError = true;
UpdateServiceView();
}
- private void SetCantDisplay() {
- SetCantDisplay("Service Not Started", "Start the Ziti Tunnel Service to get started");
- }
+
+// private void SetCantDisplay(string msg) {
+// //SetCantDisplay("Service Not Started", msg, Visibility.Visible);
+// ShowServiceNotStarted();
+// }
private void TargetNotifyIcon_Click(object sender, EventArgs e) {
this.Show();
+ System.Windows.Forms.MouseEventArgs mea = (System.Windows.Forms.MouseEventArgs)e;
+ /*if (mea.cli mea.RightButton) {
+ } else {
+
+ }*/
this.Activate();
}
@@ -148,9 +179,9 @@ private void UpdateServiceView() {
}
}
- private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
+ async private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
// add a new service client
- serviceClient = new Client();
+ serviceClient = new DataClient();
serviceClient.OnClientConnected += ServiceClient_OnClientConnected;
serviceClient.OnClientDisconnected += ServiceClient_OnClientDisconnected;
serviceClient.OnIdentityEvent += ServiceClient_OnIdentityEvent;
@@ -158,6 +189,10 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
serviceClient.OnServiceEvent += ServiceClient_OnServiceEvent;
serviceClient.OnTunnelStatusEvent += ServiceClient_OnTunnelStatusEvent;
+ monitorClient = new MonitorClient();
+ monitorClient.OnClientConnected += MonitorClient_OnClientConnected;
+ monitorClient.OnServiceStatusEvent += MonitorClient_OnServiceStatusEvent;
+
Application.Current.Properties.Add("ServiceClient", serviceClient);
Application.Current.Properties.Add("Identities", new List());
MainMenu.OnAttachmentChange += AttachmentChanged;
@@ -165,19 +200,135 @@ private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
IdentityMenu.OnError += IdentityMenu_OnError;
try {
- serviceClient.Connect();
- //var s = serviceClient.GetStatus();
- //LoadStatusFromService(s.Status);
+ await serviceClient.ConnectAsync();
+ await serviceClient.WaitForConnectionAsync();
} catch /*ignored for now (Exception ex) */{
- SetCantDisplay();
+ ShowServiceNotStarted();
serviceClient.Reconnect();
}
+
+ try {
+ await monitorClient.ConnectAsync();
+ await monitorClient.WaitForConnectionAsync();
+ } catch /*ignored for now (Exception ex) */{
+ monitorClient.Reconnect();
+ }
+
IdentityMenu.OnForgot += IdentityForgotten;
Placement();
}
+ private void MonitorClient_OnServiceStatusEvent(object sender, ServiceStatusEvent evt) {
+ Debug.WriteLine("MonitorClient_OnServiceStatusEvent");
+ ServiceControllerStatus status = (ServiceControllerStatus)Enum.Parse(typeof(ServiceControllerStatus), evt.Status);
+
+ switch (status) {
+ case ServiceControllerStatus.Running:
+ Logger.Info("Service is started");
+ break;
+ case ServiceControllerStatus.Stopped:
+ Logger.Info("Service is stopped");
+ ShowServiceNotStarted();
+ break;
+ case ServiceControllerStatus.StopPending:
+ Logger.Info("Service is stopping...");
+ this.Dispatcher.Invoke(async () => {
+ SetCantDisplay("The Service is Stopping", "Please wait while the service stops", Visibility.Hidden);
+ await WaitForServiceToStop(DateTime.Now + TimeSpan.FromSeconds(3));
+ });
+ break;
+ case ServiceControllerStatus.StartPending:
+ Logger.Info("Service is starting...");
+ break;
+ case ServiceControllerStatus.PausePending:
+ Logger.Warn("UNEXPECTED STATUS: PausePending");
+ break;
+ case ServiceControllerStatus.Paused:
+ Logger.Warn("UNEXPECTED STATUS: Paused");
+ break;
+ default:
+ Logger.Warn("UNEXPECTED STATUS: {0}", evt.Status);
+ break;
+ }
+ }
+
+ async private Task WaitForServiceToStop(DateTime until) {
+ //continually poll for the service to stop. If it is stuck - ask the user if they want to try to force
+ //close the service
+ while (DateTime.Now < until) {
+ await Task.Delay(2000);
+ ServiceStatusEvent resp = await monitorClient.Status();
+ if (resp.IsStopped()) {
+ // good - that's what we are waiting for...
+ return;
+ } else {
+ // bad - not stopped yet...
+ Logger.Debug("Waiting for service to stop... Still not stopped yet");
+ }
+ }
+ // real bad - means it's stuck probably. Ask the user if they want to try to force it...
+ Logger.Warn("Waiting for service to stop... Service did not reach stopped state in the expected amount of time.");
+ SetCantDisplay("The Service Appears Stuck", "Would you like to try to force close the service?", Visibility.Visible);
+ CloseErrorButton.Content = "Force Quit";
+ CloseErrorButton.Click -= CloseError;
+ CloseErrorButton.Click += ForceQuitButtonClick;
+ }
+
+ async private void ForceQuitButtonClick(object sender, RoutedEventArgs e) {
+ ServiceStatusEvent status = await monitorClient.ForceTerminate();
+ if(status.IsStopped()) {
+ //good
+ CloseErrorButton.Click += CloseError; //reset the close button...
+ CloseErrorButton.Click -= ForceQuitButtonClick;
+ } else {
+ //bad...
+ SetCantDisplay("The Service Is Still Running", "Current status is: " + status.Status, Visibility.Visible);
+ }
+ }
+
+ async private void StartZitiService(object sender, RoutedEventArgs e) {
+ try {
+ ShowLoad("Starting", "Staring the data service");
+ Logger.Info("StartZitiService");
+ var r = await monitorClient.StartServiceAsync();
+ if (r.Code != 0) {
+ Logger.Debug("ERROR: {0} : {1}", r.Message, r.Error);
+ } else {
+ Logger.Info("Service started!");
+ startZitiButtonVisible = false;
+ CloseErrorButton.Click -= StartZitiService;
+ CloseError(null, null);
+ }
+ } catch(Exception ex){
+ Logger.Info(ex, "UNEXPECTED ERROR!");
+ startZitiButtonVisible = false;
+ CloseErrorButton.Click += StartZitiService;
+ CloseErrorButton.IsEnabled = true;
+ }
+ CloseErrorButton.IsEnabled = true;
+ HideLoad();
+ }
+
+ bool startZitiButtonVisible = false;
+ private void ShowServiceNotStarted() {
+ semaphoreSlim.Wait(); //make sure the event is only added to the button once
+ CloseErrorButton.Click -= CloseError;
+ if (!startZitiButtonVisible) {
+ CloseErrorButton.Content = "Start Service";
+ startZitiButtonVisible = true;
+ CloseErrorButton.Click += StartZitiService;
+ }
+ semaphoreSlim.Release();
+ SetCantDisplay("Service Not Started", "Do you want to start the data service now?", Visibility.Visible);
+ }
+
+
+ private void MonitorClient_OnClientConnected(object sender, object e) {
+ Debug.WriteLine("MonitorClient_OnClientConnected");
+ }
+
private void LogLevelChanged(string level) {
- serviceClient.SetLogLevel(level);
+ serviceClient.SetLogLevelAsync(level).Wait();
}
private void IdentityMenu_OnError(string message) {
@@ -198,7 +349,11 @@ private void ServiceClient_OnClientConnected(object sender, object e) {
private void ServiceClient_OnClientDisconnected(object sender, object e) {
this.Dispatcher.Invoke(() => {
IdList.Children.Clear();
- SetCantDisplay();
+ if (e != null) {
+ Logger.Debug(e.ToString());
+ }
+ //SetCantDisplay("Start the Ziti Tunnel Service to continue");
+ ShowServiceNotStarted();
});
}
@@ -256,7 +411,7 @@ public void SetSpeed(decimal bytes, Label speed, Label speedLabel) {
private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) {
if (e == null) return;
-
+
Debug.WriteLine($"==== ServiceEvent : action:{e.Action} fingerprint:{e.Fingerprint} name:{e.Service.Name} ");
this.Dispatcher.Invoke(() => {
var found = identities.Find(id => id.Fingerprint == e.Fingerprint);
@@ -269,8 +424,11 @@ private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) {
if (e.Action == "added") {
ZitiService zs = new ZitiService(e.Service);
var svc = found.Services.Find(s => s.Name == zs.Name);
- if (svc == null) found.Services.Add(zs);
- else Debug.WriteLine("the service named " + zs.Name + " is already accounted for on this identity.");
+ if (svc == null) {
+ found.Services.Add(zs);
+ } else {
+ Debug.WriteLine("the service named " + zs.Name + " is already accounted for on this identity.");
+ }
} else {
Debug.WriteLine("removing the service named: " + e.Service.Name);
found.Services.RemoveAll(s => s.Name == e.Service.Name);
@@ -286,13 +444,14 @@ private void ServiceClient_OnServiceEvent(object sender, ServiceEvent e) {
private void ServiceClient_OnTunnelStatusEvent(object sender, TunnelStatusEvent e) {
if (e == null) return; //just skip it for now...
Debug.WriteLine($"==== TunnelStatusEvent: ");
+ Application.Current.Properties.Remove("CurrentTunnelStatus");
Application.Current.Properties.Add("CurrentTunnelStatus", e.Status);
e.Status.Dump(Console.Out);
this.Dispatcher.Invoke(() => {
- if(e.ApiVersion != Client.EXPECTED_API_VERSION) {
- SetCantDisplay("Version mismatch!", "The version of the Service is not compatible");
+ if (e.ApiVersion != DataClient.EXPECTED_API_VERSION) {
+ SetCantDisplay("Version mismatch!", "The version of the Service is not compatible", Visibility.Visible);
return;
- }
+ }
this.MainMenu.LogLevel = e.Status.LogLevel;
InitializeTimer((int)e.Status.Duration);
LoadStatusFromService(e.Status);
@@ -362,7 +521,8 @@ private void LoadStatusFromService(TunnelStatus status) {
}
LoadIdentities(true);
} else {
- SetCantDisplay();
+ //SetCantDisplay("Start the Ziti Tunnel Service to continue");
+ ShowServiceNotStarted();
}
}
@@ -384,17 +544,17 @@ private void SetNotifyIcon(string iconPrefix) {
Application.Current.MainWindow.Icon = System.Windows.Media.Imaging.BitmapFrame.Create(iconUri);
}
- private void LoadIdentities(Boolean repaint) {
+ private void LoadIdentities(Boolean repaint) {
IdList.Children.Clear();
IdList.Height = 0;
- IdList.MaxHeight = _maxHeight-520;
- ZitiIdentity[] ids = identities.ToArray();
+ IdList.MaxHeight = _maxHeight - 520;
+ ZitiIdentity[] ids = identities.OrderBy(i => i.Name.ToLower()).ToArray();
double height = 490 + (ids.Length * 60);
if (height > _maxHeight) height = _maxHeight;
this.Height = height;
- IdentityMenu.SetHeight(this.Height-160);
+ IdentityMenu.SetHeight(this.Height - 160);
bool isActive = false;
- for (int i=0; i9)?hours.ToString():"0"+hours;
- var minutesString = (minutes>9)? minutes.ToString():"0"+minutes;
- var secondsString = (seconds>9) ? seconds.ToString() : "0"+seconds;
- ConnectedTime.Content = hoursString+":"+minutesString+":"+secondsString;
+ var hoursString = (hours > 9) ? hours.ToString() : "0" + hours;
+ var minutesString = (minutes > 9) ? minutes.ToString() : "0" + minutes;
+ var secondsString = (seconds > 9) ? seconds.ToString() : "0" + seconds;
+ ConnectedTime.Content = hoursString + ":" + minutesString + ":" + secondsString;
}
private void InitializeTimer(int millisAgoStarted) {
- _startDate = DateTime.Now.Subtract(new TimeSpan(0,0,0,0, millisAgoStarted));
- _timer = new System.Windows.Forms.Timer();
- _timer.Interval = 100;
- _timer.Tick += OnTimedEvent;
- _timer.Enabled = true;
- _timer.Start();
- }
- private void Connect(object sender, RoutedEventArgs e) {
+ _startDate = DateTime.Now.Subtract(new TimeSpan(0, 0, 0, 0, millisAgoStarted));
+ _tunnelUptimeTimer = new System.Windows.Forms.Timer();
+ _tunnelUptimeTimer.Interval = 100;
+ _tunnelUptimeTimer.Tick += OnTimedEvent;
+ _tunnelUptimeTimer.Enabled = true;
+ _tunnelUptimeTimer.Start();
+ }
+ private void ConnectButtonClick(object sender, RoutedEventArgs e) {
if (!_isServiceInError) {
- ShowLoad();
- this.Dispatcher.Invoke(() => {
+ ShowLoad("Starting Service", "Please wait while the service is started...");
+ this.Dispatcher.Invoke(async () => {
//Dispatcher.Invoke(new Action(() => { }), System.Windows.Threading.DispatcherPriority.ContextIdle);
- DoConnect();
+ await DoConnectAsync();
HideLoad();
});
}
}
- private void DoConnect() {
+ async private Task DoConnectAsync() {
try {
serviceClient.SetTunnelState(true);
SetNotifyIcon("green");
@@ -574,7 +733,7 @@ private void DoConnect() {
DisconnectButton.Visibility = Visibility.Visible;
for (int i = 0; i < identities.Count; i++) {
- serviceClient.IdentityOnOff(identities[i].Fingerprint, true);
+ await serviceClient.IdentityOnOffAsync(identities[i].Fingerprint, true);
}
for (int i = 0; i < IdList.Children.Count; i++) {
IdentityItem item = IdList.Children[i] as IdentityItem;
@@ -582,39 +741,52 @@ private void DoConnect() {
item.RefreshUI();
}
} catch (ServiceException se) {
- ShowError("Error Occurred", se.Message+" "+se.AdditionalInfo);
+ ShowError("Error Occurred", se.Message + " " + se.AdditionalInfo);
} catch (Exception ex) {
ShowError("Unexpected Error", "Code 3:" + ex.Message);
}
}
- private void Disconnect(object sender, RoutedEventArgs e) {
- if (!_isServiceInError) {
- ShowLoad();
- try {
- ConnectedTime.Content = "00:00:00";
- _timer.Stop();
- serviceClient.SetTunnelState(false);
- SetNotifyIcon("white");
- ConnectButton.Visibility = Visibility.Visible;
- DisconnectButton.Visibility = Visibility.Collapsed;
- for (int i = 0; i < identities.Count; i++) {
- serviceClient.IdentityOnOff(identities[i].Fingerprint, false);
- }
- for (int i = 0; i < IdList.Children.Count; i++) {
- IdentityItem item = IdList.Children[i] as IdentityItem;
- item._identity.IsEnabled = false;
- item.RefreshUI();
- }
- } catch (ServiceException se) {
- ShowError(se.AdditionalInfo, se.Message);
- } catch (Exception ex) {
- ShowError("Unexpected Error", "Code 4:" + ex.Message);
- }
- HideLoad();
+ async private void Disconnect(object sender, RoutedEventArgs e) {
+
+ ShowLoad("Disabling Service", "Please wait for the service to stop.");
+ var r = await monitorClient.StopServiceAsync();
+ if (r.Error != null && int.Parse(r.Error) != 0) {
+ Logger.Debug("ERROR: {0}", r.Message);
+ } else {
+ Logger.Info("Service stopped!");
}
- }
- private void ShowLoad() {
+ /*
+ if (!_isServiceInError) {
+ try {
+ ShowLoad();
+ ConnectedTime.Content = "00:00:00";
+ _tunnelUptimeTimer.Stop();
+ serviceClient.SetTunnelState(false);
+ SetNotifyIcon("white");
+ ConnectButton.Visibility = Visibility.Visible;
+ DisconnectButton.Visibility = Visibility.Collapsed;
+ for (int i = 0; i < identities.Count; i++) {
+ await serviceClient.IdentityOnOffAsync(identities[i].Fingerprint, false);
+ }
+ for (int i = 0; i < IdList.Children.Count; i++) {
+ IdentityItem item = IdList.Children[i] as IdentityItem;
+ item._identity.IsEnabled = false;
+ item.RefreshUI();
+ }
+ } catch (ServiceException se) {
+ ShowError(se.AdditionalInfo, se.Message);
+ } catch (Exception ex) {
+ ShowError("Unexpected Error", "Code 4:" + ex.Message);
+ }
+ HideLoad();
+ }*/
+ HideLoad();
+ }
+
+ private void ShowLoad(string title, string msg) {
+ LoadingDetails.Text = msg;
+ LoadingTitle.Content = title;
LoadProgress.IsIndeterminate = true;
LoadingScreen.Visibility = Visibility.Visible;
((MainWindow)System.Windows.Application.Current.MainWindow).UpdateLayout();
@@ -646,6 +818,7 @@ private void ShowError(String title, String message) {
private void CloseError(object sender, RoutedEventArgs e) {
ErrorView.Visibility = Visibility.Collapsed;
NoServiceView.Visibility = Visibility.Collapsed;
+ CloseErrorButton.IsEnabled = true;
}
private void CloseApp(object sender, RoutedEventArgs e) {
@@ -666,18 +839,15 @@ private void Label_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
Placement();
}
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- serviceClient.SetLogLevel(NextLevel());
+ async private void Button_Click(object sender, RoutedEventArgs e) {
+ await serviceClient.SetLogLevelAsync(NextLevel());
}
int cur = 0;
LogLevelEnum[] levels = new LogLevelEnum[] { LogLevelEnum.FATAL, LogLevelEnum.ERROR, LogLevelEnum.WARN, LogLevelEnum.INFO, LogLevelEnum.DEBUG, LogLevelEnum.TRACE, LogLevelEnum.VERBOSE };
- public LogLevelEnum NextLevel()
- {
+ public LogLevelEnum NextLevel() {
cur++;
- if (cur > 6)
- {
+ if (cur > 6) {
cur = 0;
}
return levels[cur];
@@ -686,5 +856,20 @@ public LogLevelEnum NextLevel()
private void IdList_LayoutUpdated(object sender, EventArgs e) {
Placement();
}
+ /*
+ string sstatus = "stop";
+ async private void Button_Click_1(object sender, RoutedEventArgs e) {
+ ServiceStatusEvent r = null;
+ if (sstatus == "Stopped") {
+ r = await monitorClient.StartServiceAsync();
+ } else {
+ r = await monitorClient.StopServiceAsync();
+ }
+ sstatus = r.Status;
+ }
+ async private void Button_Click_2(object sender, RoutedEventArgs e) {
+ Logger.Info("button 2!");
+ await Task.Delay(10);
+ }*/
}
}
diff --git a/DesktopEdge/Models/ZitiIdentity.cs b/DesktopEdge/Models/ZitiIdentity.cs
index 187066f86..350b4d526 100644
--- a/DesktopEdge/Models/ZitiIdentity.cs
+++ b/DesktopEdge/Models/ZitiIdentity.cs
@@ -30,7 +30,7 @@ public ZitiIdentity(string Name, string ControllerUrl, bool IsEnabled, List
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace Ziti.Desktop.Edge.Properties {
- using System;
-
-
- ///
- /// A strongly-typed resource class, for looking up localized strings, etc.
- ///
- // This class was auto-generated by the StronglyTypedResourceBuilder
- // class via a tool like ResGen or Visual Studio.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- internal class Resources {
-
- private static global::System.Resources.ResourceManager resourceMan;
-
- private static global::System.Globalization.CultureInfo resourceCulture;
-
- [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- internal Resources() {
- }
-
- ///
- /// Returns the cached ResourceManager instance used by this class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Resources.ResourceManager ResourceManager {
- get {
- if (object.ReferenceEquals(resourceMan, null)) {
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ziti.Desktop.Edge.Properties.Resources", typeof(Resources).Assembly);
- resourceMan = temp;
- }
- return resourceMan;
- }
- }
-
- ///
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- ///
- [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
- internal static global::System.Globalization.CultureInfo Culture {
- get {
- return resourceCulture;
- }
- set {
- resourceCulture = value;
- }
- }
- }
-}
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Ziti.Desktop.Edge.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ziti.Desktop.Edge.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/DesktopEdge/Properties/Settings.Designer.cs b/DesktopEdge/Properties/Settings.Designer.cs
index bd88d5245..c0fab6e41 100644
--- a/DesktopEdge/Properties/Settings.Designer.cs
+++ b/DesktopEdge/Properties/Settings.Designer.cs
@@ -1,26 +1,26 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace Ziti.Desktop.Edge.Properties {
-
-
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
-
- private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default {
- get {
- return defaultInstance;
- }
- }
- }
-}
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Ziti.Desktop.Edge.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
index eeda5c57d..38e736102 100644
--- a/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
+++ b/DesktopEdge/Views/ItemRenderers/IdentityItem.xaml.cs
@@ -1,89 +1,90 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using ZitiDesktopEdge.Models;
-
-namespace ZitiDesktopEdge {
- ///
- /// User Control to list Identities and give status
- ///
- public partial class IdentityItem:UserControl {
-
- public delegate void StatusChanged(bool attached);
- public event StatusChanged OnStatusChanged;
-
- public ZitiIdentity _identity;
- public ZitiIdentity Identity {
- get {
- return _identity;
- }
- set {
- _identity = value;
- this.RefreshUI();
- }
- }
-
- public void RefreshUI () {
- ToggleSwitch.Enabled = _identity.IsEnabled;
- IdName.Content = _identity.Name;
- IdUrl.Content = _identity.ControllerUrl;
- ServiceCount.Content = _identity.Services.Count.ToString();
- if (ToggleSwitch.Enabled) {
- ToggleStatus.Content = "ENABLED";
- } else {
- ToggleStatus.Content = "DISABLED";
- }
- }
-
- public IdentityItem() {
- InitializeComponent();
- ToggleSwitch.OnToggled += ToggleIdentity;
- }
-
- private void ToggleIdentity(bool on) {
- try {
- if (OnStatusChanged != null) {
- OnStatusChanged(on);
- }
- ServiceClient.Client client = (ServiceClient.Client)Application.Current.Properties["ServiceClient"];
- ServiceClient.Identity id = client.IdentityOnOff(_identity.Fingerprint, on);
- this.Identity.IsEnabled = on;
- if (on) {
- ToggleStatus.Content = "ENABLED";
- } else {
- ToggleStatus.Content = "DISABLED";
- }
- } catch (ServiceClient.ServiceException se) {
- MessageBox.Show(se.AdditionalInfo, se.Message);
- } catch (Exception ex) {
- MessageBox.Show("Error", ex.Message);
- }
- }
-
- private void Canvas_MouseEnter(object sender, MouseEventArgs e) {
- OverState.Opacity = 0.2;
- }
-
- private void Canvas_MouseLeave(object sender, MouseEventArgs e) {
- OverState.Opacity = 0;
- }
-
- private void OpenDetails(object sender, MouseButtonEventArgs e) {
- IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
- deets.SelectedIdentity = this;
- deets.IdDetailToggle.Enabled = this.Identity.IsEnabled;
- deets.Identity = this.Identity;
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using ZitiDesktopEdge.Models;
+using ZitiDesktopEdge.ServiceClient;
+
+namespace ZitiDesktopEdge {
+ ///
+ /// User Control to list Identities and give status
+ ///
+ public partial class IdentityItem:UserControl {
+
+ public delegate void StatusChanged(bool attached);
+ public event StatusChanged OnStatusChanged;
+
+ public ZitiIdentity _identity;
+ public ZitiIdentity Identity {
+ get {
+ return _identity;
+ }
+ set {
+ _identity = value;
+ this.RefreshUI();
+ }
+ }
+
+ public void RefreshUI () {
+ ToggleSwitch.Enabled = _identity.IsEnabled;
+ IdName.Content = _identity.Name;
+ IdUrl.Content = _identity.ControllerUrl;
+ ServiceCount.Content = _identity.Services.Count.ToString();
+ if (ToggleSwitch.Enabled) {
+ ToggleStatus.Content = "ENABLED";
+ } else {
+ ToggleStatus.Content = "DISABLED";
+ }
+ }
+
+ public IdentityItem() {
+ InitializeComponent();
+ ToggleSwitch.OnToggled += ToggleIdentity;
+ }
+
+ async private void ToggleIdentity(bool on) {
+ try {
+ if (OnStatusChanged != null) {
+ OnStatusChanged(on);
+ }
+ DataClient client = (DataClient)Application.Current.Properties["ServiceClient"];
+ DataStructures.Identity id = await client.IdentityOnOffAsync(_identity.Fingerprint, on);
+ this.Identity.IsEnabled = on;
+ if (on) {
+ ToggleStatus.Content = "ENABLED";
+ } else {
+ ToggleStatus.Content = "DISABLED";
+ }
+ } catch (DataStructures.ServiceException se) {
+ MessageBox.Show(se.AdditionalInfo, se.Message);
+ } catch (Exception ex) {
+ MessageBox.Show("Error", ex.Message);
+ }
+ }
+
+ private void Canvas_MouseEnter(object sender, MouseEventArgs e) {
+ OverState.Opacity = 0.2;
+ }
+
+ private void Canvas_MouseLeave(object sender, MouseEventArgs e) {
+ OverState.Opacity = 0;
+ }
+
+ private void OpenDetails(object sender, MouseButtonEventArgs e) {
+ IdentityDetails deets = ((MainWindow)Application.Current.MainWindow).IdentityMenu;
+ deets.SelectedIdentity = this;
+ deets.IdDetailToggle.Enabled = this.Identity.IsEnabled;
+ deets.Identity = this.Identity;
+ }
+ }
+}
diff --git a/DesktopEdge/ZitiDesktopEdge.csproj b/DesktopEdge/ZitiDesktopEdge.csproj
index 88fec2a3d..b80fa0eb1 100644
--- a/DesktopEdge/ZitiDesktopEdge.csproj
+++ b/DesktopEdge/ZitiDesktopEdge.csproj
@@ -88,7 +88,11 @@
..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+ ..\packages\NLog.4.7.5\lib\net45\NLog.dll
+
+
@@ -104,7 +108,10 @@
True
True
+
+
+
@@ -243,6 +250,9 @@
Resources.Designer.cs
+
+ Always
+
Always
diff --git a/DesktopEdge/ZitiDesktopEdge.log.config b/DesktopEdge/ZitiDesktopEdge.log.config
new file mode 100644
index 000000000..26bdc30d1
--- /dev/null
+++ b/DesktopEdge/ZitiDesktopEdge.log.config
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DesktopEdge/packages.config b/DesktopEdge/packages.config
index d4d1038f5..9001a3120 100644
--- a/DesktopEdge/packages.config
+++ b/DesktopEdge/packages.config
@@ -1,6 +1,5 @@
-
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/ZitiDesktopEdge.Client/ServiceClient/DataStructures.cs b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
similarity index 91%
rename from ZitiDesktopEdge.Client/ServiceClient/DataStructures.cs
rename to ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
index bc2b7e1a5..ad98ea70a 100644
--- a/ZitiDesktopEdge.Client/ServiceClient/DataStructures.cs
+++ b/ZitiDesktopEdge.Client/DataStructures/DataStructures.cs
@@ -5,8 +5,17 @@
/// These classes represent the data structures that are passed back and forth
/// between the service and the client.
///
-namespace ZitiDesktopEdge.ServiceClient
-{
+namespace ZitiDesktopEdge.DataStructures {
+ public enum LogLevelEnum {
+ FATAL = 0,
+ ERROR = 1,
+ WARN = 2,
+ INFO = 3,
+ DEBUG = 4,
+ TRACE = 5,
+ VERBOSE = 6,
+ }
+
public class SvcResponse
{
public int Code { get; set; }
@@ -282,4 +291,12 @@ public class IdentityEvent : ActionEvent
{
public Identity Id { get; set; }
}
+
+ public class ServiceStatusEvent : SvcResponse {
+ public string Status { get; set; }
+
+ public bool IsStopped() {
+ return "Stopped" == this.Status;
+ }
+ }
}
\ No newline at end of file
diff --git a/ZitiDesktopEdge.Client/Server/EventRegistry.cs b/ZitiDesktopEdge.Client/Server/EventRegistry.cs
new file mode 100644
index 000000000..e3b2ad543
--- /dev/null
+++ b/ZitiDesktopEdge.Client/Server/EventRegistry.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Threading;
+
+namespace ZitiDesktopEdge.Server {
+ public class EventRegistry {
+ protected static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
+
+ public static event EventHandler MyEvent;
+
+ public static void SendEventToConsumers(object objToSend) {
+ MyEvent(objToSend, null);
+ }
+ }
+}
diff --git a/ZitiDesktopEdge.Client/Server/IPCServer.cs b/ZitiDesktopEdge.Client/Server/IPCServer.cs
new file mode 100644
index 000000000..0bad502d2
--- /dev/null
+++ b/ZitiDesktopEdge.Client/Server/IPCServer.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Threading.Tasks;
+using System.IO;
+using System.IO.Pipes;
+using System.Security.Principal;
+using System.Security.AccessControl;
+
+using Newtonsoft.Json;
+using NLog;
+
+using ZitiDesktopEdge.DataStructures;
+
+namespace ZitiDesktopEdge.Server {
+ public class IPCServer {
+ public const string PipeName = @"OpenZiti\ziti-monitor\ipc";
+ public const string EventPipeName = @"OpenZiti\ziti-monitor\events";
+
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+ private static int BUFFER_SIZE = 16 * 1024;
+
+ private JsonSerializer serializer = new JsonSerializer() { Formatting = Formatting.None };
+ private string ipcPipeName;
+ private string eventPipeName;
+
+ public IPCServer() {
+ this.ipcPipeName = IPCServer.PipeName;
+ this.eventPipeName = IPCServer.EventPipeName;
+ }
+
+ async public Task startIpcServer() {
+ int idx = 0;
+
+ // Allow AuthenticatedUserSid read and write access to the pipe.
+ PipeSecurity pipeSecurity = new PipeSecurity();
+ var id = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
+ pipeSecurity.SetAccessRule(new PipeAccessRule(id, PipeAccessRights.CreateNewInstance | PipeAccessRights.ReadWrite, AccessControlType.Allow));
+
+ while (true) {
+ try {
+ var ipcPipeServer = new NamedPipeServerStream(
+ ipcPipeName,
+ PipeDirection.InOut,
+ NamedPipeServerStream.MaxAllowedServerInstances,
+ PipeTransmissionMode.Byte,
+ PipeOptions.Asynchronous | PipeOptions.WriteThrough,
+ BUFFER_SIZE,
+ BUFFER_SIZE,
+ pipeSecurity);
+
+ await ipcPipeServer.WaitForConnectionAsync();
+ Logger.Debug("Total ipc clients now at: {0}", ++idx);
+ _ = Task.Run(async () => {
+ try {
+ await handleIpcClientAsync(ipcPipeServer);
+ } catch(Exception icpe) {
+ Logger.Error(icpe, "Unexpected erorr in handleIpcClientAsync");
+ }
+ idx--;
+ Logger.Debug("Total ipc clients now at: {0}", idx);
+ });
+ } catch (Exception pe) {
+ Logger.Error(pe, "Unexpected erorr when connecting a client pipe.");
+ }
+ }
+ }
+ async public Task startEventsServer() {
+ int idx = 0;
+
+ // Allow AuthenticatedUserSid read and write access to the pipe.
+ PipeSecurity pipeSecurity = new PipeSecurity();
+ var id = new SecurityIdentifier(WellKnownSidType.AuthenticatedUserSid, null);
+ pipeSecurity.SetAccessRule(new PipeAccessRule(id, PipeAccessRights.CreateNewInstance | PipeAccessRights.ReadWrite, AccessControlType.Allow));
+
+ while (true) {
+ try {
+ var eventPipeServer = new NamedPipeServerStream(
+ eventPipeName,
+ PipeDirection.InOut,
+ NamedPipeServerStream.MaxAllowedServerInstances,
+ PipeTransmissionMode.Byte,
+ PipeOptions.Asynchronous | PipeOptions.WriteThrough,
+ BUFFER_SIZE,
+ BUFFER_SIZE,
+ pipeSecurity);
+
+ await eventPipeServer.WaitForConnectionAsync();
+ Logger.Debug("Total event clients now at: {0}", ++idx);
+ _ = Task.Run(async () => {
+ try {
+ await handleEventClientAsync(eventPipeServer);
+ } catch (Exception icpe) {
+ Logger.Error(icpe, "Unexpected erorr in handleEventClientAsync");
+ }
+ idx--;
+ Logger.Debug("Total event clients now at: {0}", idx);
+ });
+ } catch (Exception pe) {
+ Logger.Error(pe, "Unexpected erorr when connecting a client pipe.");
+ }
+ }
+ }
+
+ async public Task handleIpcClientAsync(NamedPipeServerStream ss) {
+ using (ss) {
+ try {
+ StreamReader reader = new StreamReader(ss);
+ StreamWriter writer = new StreamWriter(ss);
+
+ string line = await reader.ReadLineAsync();
+
+ while (line != null) {
+ await processMessageAsync(line, writer);
+ line = await reader.ReadLineAsync();
+ }
+
+ Logger.Debug("handleIpcClientAsync is complete");
+ } catch (Exception e) {
+ Logger.Error(e, "Unexpected erorr when reading from or writing to a client pipe.");
+ }
+ }
+ }
+
+ async public Task handleEventClientAsync(NamedPipeServerStream ss) {
+ using (ss) {
+
+ StreamWriter writer = new StreamWriter(ss);
+ EventHandler eh = async (object sender, EventArgs e) => {
+ await writer.WriteLineAsync(sender.ToString());
+ await writer.FlushAsync();
+ };
+
+ ServiceStatusEvent status = new ServiceStatusEvent() {
+ //Op="status", Status = ServiceActions.ServiceStatus()
+ Code = 0,
+ Error = null,
+ Message = "Success",
+ Status = ServiceActions.ServiceStatus()
+ };
+ await writer.WriteLineAsync(JsonConvert.SerializeObject(status));
+ await writer.FlushAsync();
+
+ EventRegistry.MyEvent += eh;
+ try {
+ StreamReader reader = new StreamReader(ss);
+
+ string line = await reader.ReadLineAsync();
+ while (line != null) {
+ await processMessageAsync(line, writer);
+ line = await reader.ReadLineAsync();
+ }
+
+ Logger.Debug("handleEventClientAsync is complete");
+ } catch (Exception e) {
+ Logger.Error(e, "Unexpected erorr when reading from or writing to a client pipe.");
+ }
+ EventRegistry.MyEvent -= eh;
+ }
+ }
+
+ async public Task processMessageAsync(string msg, StreamWriter writer) {
+ Logger.Debug("message received: {0}", msg);
+ var r = new SvcResponse();
+ var rr = new ServiceStatusEvent();
+ try {
+ ActionEvent ae = serializer.Deserialize(new JsonTextReader(new StringReader(msg)));
+ Logger.Info("Op: {0}", ae.Op);
+ switch (ae.Op.ToLower()) {
+ case "stop":
+ if (ae.Action == "Force") {
+ // attempt to forcefully find the process and terminate it...
+ Logger.Warn("User has requested a FORCEFUL termination of the service. It must be stuck. Current status: {0}", ServiceActions.ServiceStatus());
+ var procs = System.Diagnostics.Process.GetProcessesByName("ziti-tunnel");
+ if (procs == null || procs.Length == 0) {
+ Logger.Error("Process not found! Cannot terminate!");
+ rr.Code = -20;
+ rr.Error = "Process not found! Cannot terminate!";
+ rr.Message = "Could not terminate the service forcefully";
+ break;
+ }
+
+ foreach(var p in procs) {
+ Logger.Warn("Forcefully terminating process: {0}", p.Id);
+ p.Kill();
+ }
+ rr.Message = "Service has been terminated";
+ rr.Status = ServiceActions.ServiceStatus();
+ r = rr;
+ } else {
+ r.Message = ServiceActions.StopService();
+ }
+ break;
+ case "start":
+ r.Message = ServiceActions.StartService();
+ break;
+ case "status":
+ rr.Status = ServiceActions.ServiceStatus();
+ r = rr;
+ break;
+ default:
+ msg = string.Format("UNKNOWN ACTION received: {0}", ae.Op);
+ Logger.Error(msg);
+ r.Code = -3;
+ r.Error = msg;
+ break;
+ }
+ } catch (Exception e) {
+ Logger.Error(e, "Unexpected erorr in processMessage!");
+ r.Code = -2;
+ r.Error = e.Message + ":" + e?.InnerException?.Message;
+ }
+ Logger.Info("Returning status: {0}", r.Message);
+ await writer.WriteLineAsync(JsonConvert.SerializeObject(r));
+ await writer.FlushAsync();
+ }
+ }
+}
diff --git a/ZitiDesktopEdge.Client/Server/ServiceActions.cs b/ZitiDesktopEdge.Client/Server/ServiceActions.cs
new file mode 100644
index 000000000..3a6bd159d
--- /dev/null
+++ b/ZitiDesktopEdge.Client/Server/ServiceActions.cs
@@ -0,0 +1,31 @@
+using System.ServiceProcess;
+
+using NLog;
+
+namespace ZitiDesktopEdge.Server {
+ public static class ServiceActions {
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+ private static ServiceController sc = new ServiceController("ziti");
+ public static string ServiceStatus() {
+ var status = sc.Status;
+ return status.ToString();
+ }
+
+ public static string StartService() {
+ Logger.Info("request to start ziti service received... processing...");
+ sc.Start();
+ sc.WaitForStatus(ServiceControllerStatus.Running, new System.TimeSpan(0,0,30));
+ Logger.Info("request to start ziti service received... complete...");
+ return ServiceStatus();
+ }
+
+ public static string StopService() {
+ Logger.Info("request to stop ziti service received... processing...");
+ sc.Stop();
+ sc.WaitForStatus(ServiceControllerStatus.Stopped, new System.TimeSpan(0, 0, 30));
+ Logger.Info("request to stop ziti service received... complete...");
+ return ServiceStatus();
+ }
+ }
+}
diff --git a/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs
new file mode 100644
index 000000000..4e47f1158
--- /dev/null
+++ b/ZitiDesktopEdge.Client/ServiceClient/AbstractClient.cs
@@ -0,0 +1,258 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Pipes;
+using System.Security.Principal;
+using System.Security.AccessControl;
+using System.Threading;
+using System.Threading.Tasks;
+
+using Newtonsoft.Json;
+using NLog;
+
+
+using ZitiDesktopEdge.DataStructures;
+
+namespace ZitiDesktopEdge.ServiceClient {
+ public abstract class AbstractClient {
+
+ private bool _extendedDebug = false; //set ZITI_EXTENDED_DEBUG env var to true if you want to diagnose issues with the service comms
+
+ protected NamedPipeClientStream pipeClient = null;
+ protected NamedPipeClientStream eventClient = null;
+ protected StreamWriter ipcWriter = null;
+ protected StreamReader ipcReader = null;
+ protected abstract Task ConnectPipesAsync();
+ protected abstract void ProcessLine(string line);
+ protected abstract Logger Logger { get; }
+
+ protected const string localPipeServer = ".";
+ protected const int ServiceConnectTimeout = 500;
+
+ //protected object namedPipeSyncLock = new object();
+ protected static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);
+
+ protected JsonSerializer serializer = new JsonSerializer() { Formatting = Formatting.None };
+
+ protected virtual void ClientConnected(object e) {
+ Connected = true;
+ Reconnecting = false;
+ CleanShutdown = false;
+ Logger.Debug("Client connected successfully. Setting CleanShutdown set to false.");
+
+ ipcWriter = new StreamWriter(pipeClient);
+ ipcReader = new StreamReader(pipeClient);
+ Task.Run(async () => { //hack for now until it's async...
+ try {
+ StreamReader eventReader = new StreamReader(eventClient);
+ while (true) {
+ if (eventReader.EndOfStream) {
+ break;
+ }
+
+ try {
+ string respAsString = await readMessageAsync(eventReader, "ClientConnected");
+ ProcessLine(respAsString);
+ } catch (Exception ex) {
+ Logger.Warn(ex, "ERROR caught");
+ }
+ }
+ } catch (Exception ex) {
+ Logger.Debug("unepxected error: " + ex.ToString());
+ }
+
+ // since this thread is always sitting waiting to read
+ // it should be the only one triggering this event
+ ClientDisconnected(null);
+ });
+ OnClientConnected?.Invoke(this, e);
+ }
+
+ protected virtual void ClientDisconnected(object e) {
+ Reconnect();
+ Connected = false;
+ OnClientDisconnected?.Invoke(this, e);
+ }
+
+ protected virtual void ShutdownEvent(StatusEvent e) {
+ Logger.Debug("Clean shutdown detected from ziti");
+ CleanShutdown = true;
+ OnShutdownEvent?.Invoke(this, e);
+ }
+
+ async protected Task sendAsync(object objToSend) {
+ bool retried = false;
+ while (true) {
+ try {
+ string toSend = JsonConvert.SerializeObject(objToSend, Formatting.None);
+
+ if (toSend?.Trim() != null) {
+ debugServiceCommunication("=============== sending message =============== ");
+ debugServiceCommunication(toSend);
+ await ipcWriter.WriteAsync(toSend);
+ await ipcWriter.WriteAsync('\n');
+ debugServiceCommunication("=============== flushing message =============== ");
+ await ipcWriter.FlushAsync();
+ debugServiceCommunication("=============== sent message =============== ");
+ debugServiceCommunication("");
+ debugServiceCommunication("");
+ } else {
+ Logger.Debug("NOT sending empty object??? " + objToSend?.ToString());
+ }
+ break;
+ } catch (IOException ioe) {
+ //almost certainly a problem with the pipe - recreate the pipe... try one more time.
+ //setupPipe();
+ if (retried) {
+ //we tried - throw the error...
+ throw ioe;
+ } else {
+ retried = true; //fall back through to the while and try again
+ }
+ } catch (Exception ex) {
+ //if this fails it's usually because the writer is null/invalid. throwing IOException
+ //will trigger the pipe to rebuild
+ throw new IOException("Unexpected error when sending data to service. " + ex.Message);
+ }
+ }
+ }
+
+ public event EventHandler