From 42c5823fc17e56339ffbe3935843ad4fd647a6fd Mon Sep 17 00:00:00 2001 From: MrMelon Date: Tue, 23 Mar 2021 16:49:13 +0000 Subject: [PATCH] Destroy all open notifications on close and save daemon restarting state --- MelonVPNClient/MainWindow.cs | 24 ++++-- MelonVPNClient/MelonVPNClient.csproj | 10 +++ MelonVPNClient/NotificationThreadMap.cs | 24 ++++++ .../libappindicator3sharpglue-12.10.0.so | Bin 0 -> 13880 bytes MelonVPNCore/DaemonSocketServer.cs | 51 ++++++----- MelonVPNCore/Json.cs | 80 ++++++++++++++++++ MelonVPNCore/MelonVPNCore.csproj | 1 + install-components | 1 + 8 files changed, 157 insertions(+), 34 deletions(-) create mode 100644 MelonVPNClient/NotificationThreadMap.cs create mode 100644 MelonVPNClient/net-libs/libappindicator3sharpglue-12.10.0.so create mode 100644 MelonVPNCore/Json.cs diff --git a/MelonVPNClient/MainWindow.cs b/MelonVPNClient/MainWindow.cs index 188b4a4..c2ccf63 100644 --- a/MelonVPNClient/MainWindow.cs +++ b/MelonVPNClient/MainWindow.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Net.NetworkInformation; using System.Reflection; @@ -24,7 +25,8 @@ public partial class MainWindow : Window private Button restartToggleBtn; private bool ConnectedToVPN; private bool IsHidden; - private bool RestartMode = false; + private bool RestartMode; + private List CurrentNotifications; public static readonly string MelonIconImg = "MiniMelonVPNIcon.png"; public static readonly string MelonOnlineImg = "MiniMelonVPNOnline.png"; @@ -33,6 +35,8 @@ public partial class MainWindow : Window Build(); + CurrentNotifications = new List(); + Title = "Melon VPN"; UpdateIcon(MelonIconImg); SetSizeRequest(300, 300); @@ -280,25 +284,26 @@ public partial class MainWindow : Window { string msg = (current ? "Connected to" : "Disconnected from") + " the VPN"; string icon = "/usr/lib/melon-vpn/MiniMelonVPN" + (current ? "Online" : "Icon") + ".png"; - Notification pop = new Notification("Melon VPN", msg, icon); - pop.Show(); - CloseNotificationAfterWait(pop, 1000); + Notification notification = new Notification("Melon VPN", msg, icon); + notification.Show(); + CloseNotificationAfterWait(notification, 1000); } } - void CloseNotificationAfterWait(Notification pop, int timeout) + void CloseNotificationAfterWait(Notification notification, int timeout) { // Close the notification after a wait // so it doesn't hang around - Thread wait = new Thread(() => + Thread closeTimer = new Thread(() => { Thread.Sleep(timeout); - pop.Close(); + notification.Close(); }) { IsBackground = true }; - wait.Start(); + CurrentNotifications.Add(new NotificationThreadMap(notification, closeTimer)); + closeTimer.Start(); } void SendToTray() @@ -357,6 +362,9 @@ public partial class MainWindow : Window wrapper.Join(); } + // Destroy of all temporary notifications and the close timers + foreach(NotificationThreadMap map in CurrentNotifications) map.Dispose(); + // Destroy the tray icon first if (trayIcon != null) trayIcon.Dispose(); Application.Quit(); diff --git a/MelonVPNClient/MelonVPNClient.csproj b/MelonVPNClient/MelonVPNClient.csproj index 894c21f..62f9ff8 100644 --- a/MelonVPNClient/MelonVPNClient.csproj +++ b/MelonVPNClient/MelonVPNClient.csproj @@ -19,6 +19,15 @@ prompt 4 x86 + + + + AfterBuild + cp "${SolutionDir}/MelonVPNClient/net-libs/libappindicator3sharpglue-12.10.0.so" "${TargetDir}/libappindicator3sharpglue-12.10.0.so" + ${SolutionDir} + + + true @@ -88,6 +97,7 @@ + diff --git a/MelonVPNClient/NotificationThreadMap.cs b/MelonVPNClient/NotificationThreadMap.cs new file mode 100644 index 0000000..6106532 --- /dev/null +++ b/MelonVPNClient/NotificationThreadMap.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading; +using Notify; + +namespace MelonVPNClient +{ + public class NotificationThreadMap : IDisposable + { + private readonly Notification notification; + private readonly Thread thread; + + public NotificationThreadMap(Notification notification, Thread thread) + { + this.notification = notification; + this.thread = thread; + } + + public void Dispose() + { + thread.Abort(); + notification.Close(); + } + } +} diff --git a/MelonVPNClient/net-libs/libappindicator3sharpglue-12.10.0.so b/MelonVPNClient/net-libs/libappindicator3sharpglue-12.10.0.so new file mode 100644 index 0000000000000000000000000000000000000000..dcd2e33ec760bc172cb42fe3ab5fda8ef8ad9348 GIT binary patch literal 13880 zcmeHOO>7ip82*-0*~(ABKtwQfB{cyf!)~E3fpOkF6w4b?LjK@VydnMF6a;S-r7_PE zo+Uisq~rtBQM2I~d7OD}U>WR<+zJ@ZiF`+I`=zj+k%R;y9|+zs@pznnwm|k{(%(wD z%*y+8$ke9U9v>GO4FUN}B88gY2- z$@k8=`nLotmctauEE9cn1wYSgxqR+_IsXar-$$!iZK4Vlo=;e8yE59S+b!Q|`nIj? zBgcpAlG}7EUdwlz$A_M*HR|qhr&x2N*zys3WWuq_UfrpAr(NZYjd}HwH{$q>=Dt?d zX^z=TTy{HZS6ts7bDD15w;Sbh%k@>wD=tY6`IXwZyC>IY0n$oj>fQSKK$I{8hmX>+F~5nf4%p{%aHp9{z;R-90AN*e+i} zf^~6lnzks&u;E zxtr|NN%RZ+?llUQjqaXvJSuf5H#MU|4VKJ0jOmkBKr5gX&0>H2u`#uM-J0|z`Y_1c z2kE%^QxJro6gO-PpU)P4m`52cPI0hPp|Q6it^gu8p&qPi*!s-pYiX8 z&0Fz`)nT& z8~atai;Z`~ZDM2JD!*fLLHy^%puzS_vI!OYiMPs2WVqLu;%`a(UQVX+c?4>$;8sDr zd(O&!)ivV3Ap!JzRs6JLI4t1r5F2^F1=0AhclKAY(T}A6V}SkWf4M<3VhrS*fqbs7 zuj~#K_80oI1N{S!jpPdDTrOYA7D|P}fSYsrjFMX%uQ214hi;!yMyuNLo4!+2M!n&? zMx{P(6vw?k7^6q6&`ze5`XIHfV6ayavI? zdd-rL+Xf%^4G{MUrGy3R7h?F*$zp{{+RkP28vWy#?@o;RBNTSqXkd zo-;r(K}WM~97^!BLI6T9Gyog;LV|A!A2Z-@ literal 0 HcmV?d00001 diff --git a/MelonVPNCore/DaemonSocketServer.cs b/MelonVPNCore/DaemonSocketServer.cs index 54ef645..bd59923 100644 --- a/MelonVPNCore/DaemonSocketServer.cs +++ b/MelonVPNCore/DaemonSocketServer.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using System.Net; using System.Net.Sockets; using System.Text; @@ -9,12 +10,19 @@ namespace MelonVPNCore { public static class DaemonSocketServer { - private static Process currentVpnProcess = null; - private static bool shouldBeRunning = false; - private static bool shouldRestart = false; - private static bool isRestarting = false; - private static int startingTime = 3000; - private static int restartDelay = 250; + private static Process currentVpnProcess; + private static bool shouldBeRunning; + private static bool shouldRestart; + private static bool isRestarting; + private const int startingTime = 3000; + private const int restartDelay = 250; + private static DaemonConfig config; + public const string daemonConfigPath = "/etc/melon-vpn/daemon.cfg"; + + private static void SaveConfig() + { + File.WriteAllText(daemonConfigPath, config.ToJson()); + } public static void StartServer() { @@ -22,11 +30,13 @@ namespace MelonVPNCore IPAddress ipAddress = host.AddressList[0]; IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 22035); + if (File.Exists(daemonConfigPath)) config = DaemonConfig.FromJson(File.ReadAllText(daemonConfigPath)); + else config = new DaemonConfig(); + try { Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp); listener.Bind(localEndPoint); - listener.Listen(32); string lastClientUpdate = Messages.EOF; @@ -53,17 +63,19 @@ namespace MelonVPNCore else if (data == Messages.RestartOnMsg) { shouldRestart = true; + SaveConfig(); Client.SendDataMessage(DataMessage.RestartOn, true); } else if (data == Messages.RestartOffMsg) { shouldRestart = false; + SaveConfig(); Client.SendDataMessage(DataMessage.RestartOff, true); } else if (data == Messages.StatusMsg) { Console.WriteLine("Status requested"); - if (isProcessOnline(currentVpnProcess) || shouldBeRunning) + if (IsProcessOnline(currentVpnProcess) || shouldBeRunning) { if (isRestarting) { @@ -88,7 +100,7 @@ namespace MelonVPNCore } else if (data == Messages.StartMsg) { - if (! isProcessOnline(currentVpnProcess)) + if (! IsProcessOnline(currentVpnProcess)) { shouldBeRunning = true; Console.WriteLine("Starting VPN"); @@ -125,7 +137,7 @@ namespace MelonVPNCore { shouldBeRunning = false; bool haderr = false; - if (isProcessOnline(currentVpnProcess)) + if (IsProcessOnline(currentVpnProcess)) { Console.WriteLine("Stopping VPN"); try @@ -169,23 +181,10 @@ namespace MelonVPNCore } } - public static bool isProcessOnline(Process p) + public static bool IsProcessOnline(Process p) { - if (p == null) - { - return false; - } - else - { - if (p.HasExited) - { - return false; - } - else - { - return true; - } - } + if (p == null) return false; + return !p.HasExited; } static void CurrentVpnProcess_Exited(object sender, EventArgs e) diff --git a/MelonVPNCore/Json.cs b/MelonVPNCore/Json.cs new file mode 100644 index 0000000..43ab1e2 --- /dev/null +++ b/MelonVPNCore/Json.cs @@ -0,0 +1,80 @@ +using System; +using System.Globalization; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace MelonVPNCore +{ + // I hate overhead but this code is just nice xD + + // Base json class with type property FromJson and ToJson methods + public class JsonBase + { + [JsonProperty("type")] + public string Type { get; set; } + + // Convert from json string to WSJson class + public static JsonBase FromJson(string json) => JsonConvert.DeserializeObject(json, Converter.Settings); + + // Convert any class into a json string + public string ToJson() => JsonConvert.SerializeObject(this, Converter.Settings); + + // Converter with settings + internal static class Converter + { + public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.Ignore, + DateParseHandling = DateParseHandling.None, + Converters = + { + new IsoDateTimeConverter{DateTimeStyles=DateTimeStyles.AssumeUniversal } + } + }; + } + } + + // Base class for custom json with a type argument + public class JsonBase : JsonBase + { + // Convert from json string to T class + public static new T FromJson(string json) => JsonConvert.DeserializeObject(json, Converter.Settings); + + // Used to convert json property into type long + internal class ParseStringConverter : JsonConverter + { + public override bool CanConvert(Type objectType) { return objectType == typeof(long) || objectType == typeof(long); } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) return null; + var value = serializer.Deserialize(reader); + if (long.TryParse(value, out long l)) return l; + throw new Exception("Cannot unmarshal type long"); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + { + serializer.Serialize(writer, null); + return; + } + var v = (long)value; + serializer.Serialize(writer, v.ToString()); + return; + } + + public static readonly ParseStringConverter Singleton = new ParseStringConverter(); + } + } + + // Class for the daemon config + public class DaemonConfig : JsonBase + { + public DaemonConfig() => Type = "DaemonConfig"; + + [JsonProperty("restart")] + public string ShouldRestart { get; set; } + } +} diff --git a/MelonVPNCore/MelonVPNCore.csproj b/MelonVPNCore/MelonVPNCore.csproj index d970afb..40b76c1 100644 --- a/MelonVPNCore/MelonVPNCore.csproj +++ b/MelonVPNCore/MelonVPNCore.csproj @@ -35,6 +35,7 @@ + diff --git a/install-components b/install-components index dca12ac..a2c92bf 100755 --- a/install-components +++ b/install-components @@ -43,6 +43,7 @@ sudo cp MelonVPNClient/bin/Release/MelonVPNClient.exe /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MelonVPNClient.exe.config /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MiniMelonVPNIcon.png /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MiniMelonVPNOnline.png /usr/lib/melon-vpn/ +sudo cp MelonVPNClient/bin/Release/MelonVPNDesktopIcon.png /usr/lib/melon-vpn/ # copy app indicator icons mkdir -p ~/.local/share/icons/hicolor/128x128/apps/