diff --git a/python_scripts/generate_exe.txt b/python_scripts/generate_exe.txt
new file mode 100644
index 0000000..7c2e853
--- /dev/null
+++ b/python_scripts/generate_exe.txt
@@ -0,0 +1,5 @@
+//DON'T USE THIS, onefile causes the file to be considered a trojan by some anti-viruses.
+pyinstaller task_manager.py --onefile
+
+pyinstaller task_manager.py
+pyinstaller get_process_icon.py
\ No newline at end of file
diff --git a/python_scripts/get_process_icon.py b/python_scripts/get_process_icon.py
new file mode 100644
index 0000000..3a86bc2
--- /dev/null
+++ b/python_scripts/get_process_icon.py
@@ -0,0 +1,55 @@
+import base64
+from io import BytesIO
+import win32ui
+import win32gui
+import win32con
+import win32api
+from PIL import Image
+from sys import argv
+import socketio
+import eventlet
+
+sio = socketio.Server()
+app = socketio.WSGIApp(sio)
+
+
+@sio.on('get_process_icon')
+def get_process_icon(sid, data):
+ try:
+ ico_x = win32api.GetSystemMetrics(win32con.SM_CXICON)
+ ico_y = win32api.GetSystemMetrics(win32con.SM_CYICON)
+ try:
+ large, small = win32gui.ExtractIconEx(data, 0)
+ except:
+ pass
+ if len(large) == 0 or len(small) == 0:
+ pass
+ win32gui.DestroyIcon(small[0])
+ hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
+ hbmp = win32ui.CreateBitmap()
+ hbmp.CreateCompatibleBitmap(hdc, ico_x, ico_x)
+ hdc = hdc.CreateCompatibleDC()
+ hdc.SelectObject(hbmp)
+ hdc.DrawIcon((0, 0), large[0])
+ bmpstr = hbmp.GetBitmapBits(True)
+ icon = Image.frombuffer(
+ 'RGBA',
+ (ico_x, ico_y),
+ bmpstr, 'raw', 'BGRA', 0, 1
+ )
+ if (ico_x > 49):
+ icon = icon.resize((50, 50))
+ icon = icon.resize((50, 50))
+ buffered = BytesIO()
+ icon.save(buffered, format="PNG")
+ a = buffered.getvalue()
+ img_str = base64.b64encode(buffered.getvalue())
+ img_str = img_str.decode("utf-8")
+ sio.emit('process_icon', {"process": data, "icon": img_str})
+ except Exception as c:
+ sio.emit('process_icon', {"process": data, "icon": None})
+
+
+if __name__ == '__main__':
+ # Run the SocketIO server using eventlet
+ eventlet.wsgi.server(eventlet.listen(('0.0.0.0', 6511)), app)
diff --git a/zal_app/lib/Screens/AuthorizedScreen/Widgets/buy_premium_widget.dart b/zal_app/lib/Screens/AuthorizedScreen/Widgets/buy_premium_widget.dart
index 7106590..1dfae6e 100644
--- a/zal_app/lib/Screens/AuthorizedScreen/Widgets/buy_premium_widget.dart
+++ b/zal_app/lib/Screens/AuthorizedScreen/Widgets/buy_premium_widget.dart
@@ -102,7 +102,7 @@ class BuyPremiumWidget extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
- "3-days trial, cancel anytime!",
+ "3-days trial!",
style: Theme.of(context).textTheme.labelMedium,
),
Text(
@@ -163,7 +163,7 @@ class BuyPremiumWidget extends ConsumerWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
- "7-days trial, cancel anytime!",
+ "7-days trial!",
style: Theme.of(context).textTheme.labelMedium,
),
Text(
@@ -180,7 +180,12 @@ class BuyPremiumWidget extends ConsumerWidget {
),
),
)),
- SizedBox(height: 9.h),
+ SizedBox(height: 2.h),
+ Text(
+ "Subscriptions will automatically renew unless canceled within 3 days before the end of the current period. you can cancel anytime through your Google Play Store settings.",
+ style: Theme.of(context).textTheme.labelSmall,
+ ),
+ SizedBox(height: 2.h),
const RestorePurchasesButton(),
],
),
@@ -207,7 +212,7 @@ class BenefitsWidget extends ConsumerWidget {
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3),
children: const [
BenefitCard(text: "Remove Ads"),
- BenefitCard(text: "better charts (coming soon)"),
+ // BenefitCard(text: "better charts (coming soon)"),
BenefitCard(text: "Support the Developer"),
],
),
diff --git a/zal_app/lib/Screens/SettingsScreen/settings_screen.dart b/zal_app/lib/Screens/SettingsScreen/settings_screen.dart
index d896742..efbcf00 100644
--- a/zal_app/lib/Screens/SettingsScreen/settings_screen.dart
+++ b/zal_app/lib/Screens/SettingsScreen/settings_screen.dart
@@ -33,7 +33,7 @@ class SettingsScreen extends ConsumerWidget {
title: "Use Celcius",
subtitle: "switch between Celcius and Fahreneit",
value: settings?['useCelcius'] ?? true,
- onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('useCelcius',value),
+ onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('useCelcius', value),
icon: const Icon(FontAwesomeIcons.temperatureHalf),
),
],
@@ -45,14 +45,14 @@ class SettingsScreen extends ConsumerWidget {
subtitle:
"your data will be used to see how the App\nbehaves on different PC Specs,this is \nextremely helpful to me, please leave it ON.",
value: settings?['sendAnalaytics'] ?? true,
- onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('sendAnalaytics',value),
+ onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('sendAnalaytics', value),
icon: const Icon(FontAwesomeIcons.paintRoller),
),
SwitchSettingUi(
title: "Personalized Ads",
subtitle: "",
value: settings?['personalizedAds'] ?? true,
- onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('personalizedAds',value),
+ onChanged: (value) => ref.read(settingsProvider.notifier).updateSettings('personalizedAds', value),
icon: const Icon(FontAwesomeIcons.paintRoller),
),
],
@@ -60,28 +60,6 @@ class SettingsScreen extends ConsumerWidget {
ref.watch(computerDataProvider).valueOrNull == null
? Container()
: SectionSettingUi(children: [
- Text("Select your primary GPU", style: Theme.of(context).textTheme.titleLarge),
- StaggeredGridview(
- children: ref.watch(computerDataProvider).valueOrNull!.availableGpus!.map((e) {
- final gpu = e;
- return GestureDetector(
- onTap: () {
- ref.read(settingsProvider.notifier).updateSettings('primaryGpuName',gpu);
- },
- child: Card(
- color: (settings?['primaryGpuName'] ?? "") == gpu ? Theme.of(context).primaryColor : Theme.of(context).cardColor,
- elevation: 5,
- shadowColor: Colors.transparent,
- child: Center(
- child: Text(
- gpu,
- maxLines: 2,
- style: Theme.of(context).textTheme.titleLarge!.copyWith(color: Theme.of(context).cardColor),
- ),
- ),
- ),
- );
- }).toList()),
Align(
alignment: Alignment.centerRight,
child: TextButton.icon(
diff --git a/zal_app/pubspec.yaml b/zal_app/pubspec.yaml
index 8ee665a..bac0e95 100644
--- a/zal_app/pubspec.yaml
+++ b/zal_app/pubspec.yaml
@@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
-version: 1.7.1+21
+version: 1.7.2+23
environment:
sdk: ">=3.2.0 <4.0.0"
diff --git a/zal_program/.gitattributes b/zal_program/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/zal_program/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/zal_program/LICENSE.md b/zal_program/LICENSE.md
new file mode 100644
index 0000000..1873b4f
--- /dev/null
+++ b/zal_program/LICENSE.md
@@ -0,0 +1,11 @@
+
+
+Copyright 2023 Hedi Hadi
+
+MIT License with Additional Restrictions
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to privately modify and use the Software, but not to distribute the Software or use it for commercial purposes.
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/zal_program/README.md b/zal_program/README.md
new file mode 100644
index 0000000..9e53347
--- /dev/null
+++ b/zal_program/README.md
@@ -0,0 +1 @@
+# Zal
\ No newline at end of file
diff --git a/zal_program/Zal.sln b/zal_program/Zal.sln
new file mode 100644
index 0000000..1a9083d
--- /dev/null
+++ b/zal_program/Zal.sln
@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33829.357
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Zal", "Zal\Zal.csproj", "{ABE23427-C720-41C8-92BD-DF87181FF3D0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2DB0CF01-2D3A-4CA1-A291-E2A3161EE683}"
+ ProjectSection(SolutionItems) = preProject
+ LICENSE.md = LICENSE.md
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ABE23427-C720-41C8-92BD-DF87181FF3D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ABE23427-C720-41C8-92BD-DF87181FF3D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ABE23427-C720-41C8-92BD-DF87181FF3D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ABE23427-C720-41C8-92BD-DF87181FF3D0}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {5C8A664D-D750-4BDF-B4D1-46D658B0CE96}
+ EndGlobalSection
+EndGlobal
diff --git a/zal_program/Zal/App.config b/zal_program/Zal/App.config
new file mode 100644
index 0000000..8395ffa
--- /dev/null
+++ b/zal_program/Zal/App.config
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ True
+
+
+
+
\ No newline at end of file
diff --git a/zal_program/Zal/App.xaml b/zal_program/Zal/App.xaml
new file mode 100644
index 0000000..9be1c12
--- /dev/null
+++ b/zal_program/Zal/App.xaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/zal_program/Zal/App.xaml.cs b/zal_program/Zal/App.xaml.cs
new file mode 100644
index 0000000..376d686
--- /dev/null
+++ b/zal_program/Zal/App.xaml.cs
@@ -0,0 +1,56 @@
+using Firebase.Auth.Providers;
+using Firebase.Auth.Repository;
+using Firebase.Auth.UI;
+using System.Threading;
+using System.Windows;
+
+namespace Zal
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ private static Mutex _mutex = null;
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ const string appName = "Zal";
+ bool createdNew;
+
+ _mutex = new Mutex(true, appName, out createdNew);
+
+ if (!createdNew)
+ {
+ //app is already running! Exiting the application
+ Application.Current.Shutdown();
+ }
+
+ base.OnStartup(e);
+ }
+ public App()
+ {
+
+ FirebaseUI.Initialize(new FirebaseUIConfig
+ {
+ ApiKey = "AIzaSyDSj8N7DH3jtMOAa4hd7ytqMq2H_8iprmc",
+ AuthDomain = "zal1-353509.firebaseapp.com",
+ Providers = new FirebaseAuthProvider[]
+ {
+ new GoogleProvider(),
+
+ new EmailProvider()
+ },
+ PrivacyPolicyUrl = "https://github.com/step-up-labs/firebase-authentication-dotnet",
+ TermsOfServiceUrl = "https://github.com/step-up-labs/firebase-database-dotnet",
+ IsAnonymousAllowed = false,
+ AutoUpgradeAnonymousUsers = true,
+ UserRepository = new FileUserRepository("FirebaseSample"),
+ // Func called when upgrade of anonymous user fails because the user already exists
+ // You should grab any data created under your anonymous user, sign in with the pending credential
+ // and copy the existing data to the new user
+ // see details here: https://github.com/firebase/firebaseui-web#upgrading-anonymous-users
+ AnonymousUpgradeConflict = conflict => conflict.SignInWithPendingCredentialAsync(true)
+ });
+ }
+ }
+}
diff --git a/zal_program/Zal/AssemblyInfo.cs b/zal_program/Zal/AssemblyInfo.cs
new file mode 100644
index 0000000..8b5504e
--- /dev/null
+++ b/zal_program/Zal/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/zal_program/Zal/Backend.cs b/zal_program/Zal/Backend.cs
new file mode 100644
index 0000000..fbd65e7
--- /dev/null
+++ b/zal_program/Zal/Backend.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using ZalConsole.HelperFunctions.SpecificFunctions;
+using Zal.Constants.Models;
+using Zal.HelperFunctions;
+
+namespace Zal
+{
+ public class Backend
+ {
+ computerDataGetter computerDataGetter = null;
+ public event EventHandler fpsDataReceived;
+ FpsDataGetter fpsDataGetter = new FpsDataGetter();
+ public Backend()
+ {
+ try
+ {
+ computerDataGetter = new computerDataGetter();
+ }
+ catch (Exception c)
+ {
+ Logger.LogError("error initializing computerDataGetter", c);
+ }
+ }
+ public async Task getComputerDataAsync()
+ {
+ return await computerDataGetter.getcomputerDataAsync();
+ }
+ public Dictionary> getGpuProcesses()
+ {
+ var gpuProcesses = GpuUtilizationGetter.getProcessesGpuUsage();
+ return gpuProcesses;
+ }
+ public void startFps(int pid)
+ {
+ _ = Task.Run(async () =>
+ {
+ fpsDataGetter.startPresentmon(pid);
+ fpsDataGetter.sendFpsData += (sender, fpsData) =>
+ {
+ var data = Newtonsoft.Json.JsonConvert.SerializeObject(fpsData);
+ fpsDataReceived.Invoke(this, data);
+ };
+ });
+ }
+ public void stopFps()
+ {
+ fpsDataGetter.stopPresentmon();
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/BatteryData.cs b/zal_program/Zal/Backend/Constants/Models/BatteryData.cs
new file mode 100644
index 0000000..847d71c
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/BatteryData.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class batteryData
+ {
+ public bool hasBattery { get; set; }
+ public uint life { get; set; }
+ public bool isCharging { get; set; }
+ public uint lifeRemaining { get; set; }
+
+
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/ComputerData.cs b/zal_program/Zal/Backend/Constants/Models/ComputerData.cs
new file mode 100644
index 0000000..43917bb
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/ComputerData.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Zal.HelperFunctions.SpecificFunctions;
+
+namespace Zal.Constants.Models
+{
+ public class computerData
+ {
+ public ramData? ramData { get; set; }
+ public cpuData? cpuData { get; set; }
+ public List gpuData { get; set; }
+ public motherboardData? motherboardData { get; set; }
+ public List? storagesData { get; set; }
+ public List? monitorsData { get; set; }
+ public batteryData? batteryData { get; set; }
+ public fpsData? fpsData { get; set; }
+ public Dictionary? taskmanagerData { get; set; }
+ public bool isAdminstrator {get;set;}
+ public Dictionary processesGpuUsage;
+ public List networkInterfaces { get; set; }
+ public networkSpeed primaryNetworkSpeed { get; set; }
+ public computerData() {
+ this.gpuData = new List();
+ this.storagesData = new List();
+ }
+ }
+
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/CpuData.cs b/zal_program/Zal/Backend/Constants/Models/CpuData.cs
new file mode 100644
index 0000000..ee391a5
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/CpuData.cs
@@ -0,0 +1,83 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class cpuData
+ {
+ public string name;
+ public cpuInfo? cpuInfo;
+ public uint temperature;
+ public uint load;
+ public ulong power;
+ public Dictionary powers = new Dictionary();
+ public Dictionary loads = new Dictionary();
+ public Dictionary voltages = new Dictionary();
+ public Dictionary clocks = new Dictionary();
+
+ public cpuData(IHardware hardware, cpuInfo? cpuInfo) {
+
+ this.cpuInfo = cpuInfo;
+ this.name = hardware.Name;
+
+ foreach (ISensor sensor in hardware.Sensors)
+ {
+ if (sensor.SensorType == SensorType.Power)
+ {
+ if (sensor.Name.Contains("Package"))
+ {
+ this.power = (ulong)sensor.Value;
+ }
+ else
+ {
+ this.powers[sensor.Name] = sensor.Value;
+ }
+ }
+ else if (sensor.SensorType == SensorType.Load)
+ {
+ if (sensor.Name == "CPU Total")
+ {
+ this.load = (uint)sensor.Value;
+ }
+ else
+ {
+ this.loads[sensor.Name] = sensor.Value;
+ }
+ }
+ else if (sensor.SensorType == SensorType.Voltage)
+ {
+ this.voltages[sensor.Name] = sensor.Value;
+ }
+ else if (sensor.SensorType == SensorType.Clock)
+ {
+ this.clocks[sensor.Name] = sensor.Value;
+ }
+ else if (sensor.SensorType == SensorType.Temperature && sensor.Name.Contains("(Tctl/Tdie)"))
+ {
+ this.temperature = (uint)sensor.Value;
+ }
+ else
+ {
+ var foundSensor = hardware.Sensors.FirstOrDefault(s => s.SensorType == SensorType.Temperature && s.Name.Contains("(Tctl/Tdie)"));
+ if (foundSensor == null)
+ {
+ foundSensor = hardware.Sensors.FirstOrDefault(s => s.SensorType == SensorType.Temperature && s.Name.Contains("Average"));
+ }
+ if (foundSensor == null)
+ {
+ foundSensor = hardware.Sensors.FirstOrDefault(s => s.SensorType == SensorType.Temperature && s.Name.Contains("Core #1"));
+ }
+ if (foundSensor != null)
+ {
+ this.temperature = (uint)foundSensor.Value;
+ }
+
+ }
+ }
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/CpuInfo.cs b/zal_program/Zal/Backend/Constants/Models/CpuInfo.cs
new file mode 100644
index 0000000..7a0fbbb
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/CpuInfo.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class cpuInfo
+ {
+ public string name { get; set; }
+ public string socket { get; set; }
+ public uint speed { get; set; }
+ public uint busSpeed { get; set; }
+ public ulong l2Cache { get; set; }
+ public ulong l3Cache { get; set; }
+ public uint cores { get; set; }
+ public uint threads { get; set; }
+
+
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/CrystalDiskInfo.cs b/zal_program/Zal/Backend/Constants/Models/CrystalDiskInfo.cs
new file mode 100644
index 0000000..856fea4
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/CrystalDiskInfo.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class crystalDiskData
+ {
+ public bool isNvme = false;
+ public Dictionary info { get; set; }
+ public List smartAttributes { get; set; }
+ }
+ public class smartAttribute
+ {
+ private string _attributeName;
+ public string id { get; set; }
+ public int? currentValue { get; set; }
+ public int? worstValue { get; set; }
+ public int? threshold { get; set; }
+ public long? rawValue { get; set; }
+ public string attributeName
+ {
+ get => _attributeName;
+ set => _attributeName = value?.Replace("'", "").Replace("\"","");
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/FilesGetterModels.cs b/zal_program/Zal/Backend/Constants/Models/FilesGetterModels.cs
new file mode 100644
index 0000000..5a7160d
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/FilesGetterModels.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+public class FileData
+{
+ private string _label;
+ public string label
+ {
+ get => _label;
+ set => _label = value?.Replace("'", "").Replace("\"", "");
+ }
+ public string directory { get; set; }
+ public long size { get; set; }
+ public string name { get; set; }
+ public string fileType { get; set; }
+public long? dateCreated { get; set; }
+ public long? dateModified { get; set; }
+
+ public string extension { get; set; }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/FpsData.cs b/zal_program/Zal/Backend/Constants/Models/FpsData.cs
new file mode 100644
index 0000000..91d078c
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/FpsData.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class fpsData
+ {
+ public string processName { get; set; }
+ public uint? processId { get; set; }
+ public double msBetweenPresents { get; set; }
+ public DateTime dateCreated { get; set; }
+ public fpsData() {
+ dateCreated = DateTime.Now;
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/GpuData.cs b/zal_program/Zal/Backend/Constants/Models/GpuData.cs
new file mode 100644
index 0000000..f8b1408
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/GpuData.cs
@@ -0,0 +1,75 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class gpuData
+ {
+ public string name { get; set; }
+ public ulong coreSpeed { get; set; }
+ public ulong memorySpeed { get; set; }
+ public uint fanSpeedPercentage { get; set; }
+ public uint corePercentage { get; set; }
+ public uint power { get; set; }
+ public ulong dedicatedMemoryUsed { get; set; }
+ public uint voltage { get; set; }
+ public uint temperature { get; set; }
+ public int fps { get;set; }
+ public gpuData(IHardware? hardware)
+ {
+
+ this.name = $"{hardware?.Name}";
+ if (hardware == null)
+ {
+ return;
+ }
+ foreach (ISensor sensor in hardware.Sensors)
+ {
+ if (sensor.SensorType == SensorType.Clock && sensor.Name == "GPU Core")
+ {
+ this.coreSpeed = (ulong)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.Clock && sensor.Name == "GPU Memory")
+ {
+ this.memorySpeed = (ulong)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.Control && sensor.Name == "GPU Fan")
+ {
+ this.fanSpeedPercentage = (uint)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.Load && sensor.Name == "GPU Core")
+ {
+ this.corePercentage = (uint)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.Power && sensor.Name == "GPU Package")
+ {
+ this.power = (uint)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.SmallData && sensor.Name == "D3D Dedicated Memory Used")
+ {
+ this.dedicatedMemoryUsed = (ulong)sensor.Value;
+ }
+ if (sensor.SensorType == SensorType.Voltage)
+ {
+ this.voltage = (uint)sensor.Value;
+
+
+ }
+ if (sensor.Name.Contains("FPS"))
+ {
+ this.fps = (int)sensor.Value;
+
+
+ }
+ if (sensor.SensorType == SensorType.Temperature)
+ {
+ this.temperature = (uint)sensor.Value;
+ }
+ }
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/MonitorData.cs b/zal_program/Zal/Backend/Constants/Models/MonitorData.cs
new file mode 100644
index 0000000..ed22b9b
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/MonitorData.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class monitorData
+ {
+ public string name { get; set; }
+ public uint height { get; set; }
+ public uint width { get; set; }
+ public bool isPrimary { get; set; }
+ public uint bitsPerPixel { get; set; }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/MotherboardData.cs b/zal_program/Zal/Backend/Constants/Models/MotherboardData.cs
new file mode 100644
index 0000000..cb5174a
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/MotherboardData.cs
@@ -0,0 +1,27 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class motherboardData
+ {
+ public string name { get;set;}
+ public uint temperature { get;set;}
+ public motherboardData(IHardware hardware)
+ {
+ this.name = hardware.Name;
+ foreach (ISensor sensor in hardware.Sensors)
+ {
+ if (sensor.SensorType == SensorType.Temperature)
+ {
+ this.temperature = (uint)sensor.Value;
+ }
+
+ }
+}
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/NetworkSpeed.cs b/zal_program/Zal/Backend/Constants/Models/NetworkSpeed.cs
new file mode 100644
index 0000000..a7e1105
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/NetworkSpeed.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class networkSpeed
+ {
+ public long download { get; set; }
+ public long upload { get; set; }
+ public networkSpeed(long download, long upload)
+ {
+ this.download = download;
+ this.upload = upload;
+ }
+
+
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/ProcessInfo.cs b/zal_program/Zal/Backend/Constants/Models/ProcessInfo.cs
new file mode 100644
index 0000000..44050c7
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/ProcessInfo.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ZalConsole.Constants.Models
+{
+ public class ProcessInfo
+ {
+ public string name { get; set; }
+ public string displayName { get; set; }
+ public bool isBlacklisted { get; set; }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/RamData.cs b/zal_program/Zal/Backend/Constants/Models/RamData.cs
new file mode 100644
index 0000000..7022935
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/RamData.cs
@@ -0,0 +1,36 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class ramData
+ {
+ public float memoryUsed;
+ public float memoryAvailable;
+ public uint memoryUsedPercentage;
+ public List? ramPiecesData;
+ public ramData(IHardware hardware, List? ramPiecesData) {
+ this.ramPiecesData = ramPiecesData;
+ foreach (ISensor sensor in hardware.Sensors)
+ {
+ if (sensor.SensorType == SensorType.Data && sensor.Name == "Memory Used")
+ {
+ this.memoryUsed = (float)sensor.Value;
+ }
+ else if (sensor.SensorType == SensorType.Data && sensor.Name == "Memory Available")
+ {
+ this.memoryAvailable = (float)sensor.Value;
+ }
+ else if (sensor.SensorType == SensorType.Load && sensor.Name == "Memory")
+ {
+ this.memoryUsedPercentage = (uint)sensor.Value;
+ }
+ }
+
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/RamPieceData.cs b/zal_program/Zal/Backend/Constants/Models/RamPieceData.cs
new file mode 100644
index 0000000..e0acee8
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/RamPieceData.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.Constants.Models
+{
+ public class ramPieceData
+ {
+ public ulong capacity;
+ public string manufacturer;
+ public string partNumber;
+ public uint speed;
+ }
+}
diff --git a/zal_program/Zal/Backend/Constants/Models/StorageData.cs b/zal_program/Zal/Backend/Constants/Models/StorageData.cs
new file mode 100644
index 0000000..4ce29ec
--- /dev/null
+++ b/zal_program/Zal/Backend/Constants/Models/StorageData.cs
@@ -0,0 +1,138 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Zal.HelperFunctions.SpecificFunctions;
+
+namespace Zal.Constants.Models
+{
+ public class storageData
+ {
+ public int diskNumber { get; set; }
+ public long totalSize { get; set; }
+ public ulong freeSpace { get; set; }
+ public ulong temperature { get; set; }
+ public double? readRate { get; set; }
+ public ulong? writeRate { get; set; }
+ //whether it's hdd, ssd, or external storage
+ public string type { get; set; }
+ public List partitions { get; } = new List();
+ public Dictionary info = new Dictionary();
+ public List smartAttributes = new List();
+ public storageData(IHardware hardware, List? crystalDiskDatas)
+ {
+ type = "External";
+ crystalDiskData? crystalDiskData = null;
+ if (crystalDiskDatas != null)
+ {
+ foreach (crystalDiskData _crystalDiskData in crystalDiskDatas)
+ {
+ if (_crystalDiskData.info["model"] == hardware.Name)
+ {
+ crystalDiskData = _crystalDiskData;
+ info = crystalDiskData.info;
+ smartAttributes = crystalDiskData.smartAttributes;
+ //if the disk has "Current Pending Sector Count" variable, it means this is hdd, it's SSD otherwise. this might not be accurate, further testing required.
+ var currentPendingSectorCount = crystalDiskData.smartAttributes.Where(smartAttribute => smartAttribute.attributeName == "SSD Life Left");
+ if (crystalDiskData.isNvme)
+ {
+ type = "NVMe";
+ }
+ else if (currentPendingSectorCount.Count() == 0)
+ {
+ type = "HDD";
+ }
+ else
+ {
+ type = "SSD";
+ }
+ }
+ }
+ }
+
+ foreach (ISensor sensor in hardware.Sensors)
+ {
+ if (sensor.SensorType == SensorType.Temperature)
+ {
+ try
+ {
+ temperature = (ulong)sensor.Value;
+ }
+ catch (Exception ex)
+ {
+
+ }
+ }
+ else if (sensor.SensorType == SensorType.Throughput && sensor.Name == "Read Rate")
+ {
+ try
+ {
+ var value = sensor.Value.ToString();
+ if (value != null)
+ {
+ readRate = ulong.Parse(sensor.Value.ToString().Split('.')[0]);
+ }
+
+ }
+ catch (Exception ex)
+ {
+
+ }
+
+ }
+ else if (sensor.SensorType == SensorType.Throughput && sensor.Name == "Write Rate")
+ {
+ try
+ {
+ writeRate = (ulong)sensor.Value;
+ }
+ catch (Exception ex)
+ {
+
+ }
+
+ }
+
+ }
+ var diskNumber = int.Parse(hardware.Identifier.ToString().Substring(hardware.Identifier.ToString().Length - 1));
+
+ try
+ {
+
+ var diskInfo = diskInfoGetter.GetdiskInfo(diskNumber, crystalDiskData);
+
+ this.diskNumber = diskNumber;
+ totalSize = diskInfo.totalSize;
+ freeSpace = diskInfo.freeSpace;
+ partitions = diskInfo.partitions;
+ }
+
+ catch (Exception ex)
+ {
+ Logger.LogError("error calling GetdiskInfo", ex);
+ }
+
+ }
+ }
+
+
+}
+public class partitionInfo
+{
+ private string _label;
+ public string driveLetter { get; set; }
+ public string label
+ {
+ get => _label;
+ set => _label = value?.Replace("'", "").Replace("\"", "");
+ }
+ public long size { get; set; }
+ public long freeSpace { get; set; }
+}
+public class diskInfo
+{
+ public int diskNumber { get; set; }
+ public long totalSize { get; set; }
+ public ulong freeSpace { get; set; }
+ public List partitions { get; } = new List();
+}
\ No newline at end of file
diff --git a/zal_program/Zal/Backend/HelperFunctions/ComputerDataGetter.cs b/zal_program/Zal/Backend/HelperFunctions/ComputerDataGetter.cs
new file mode 100644
index 0000000..d703ac5
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/ComputerDataGetter.cs
@@ -0,0 +1,247 @@
+using LibreHardwareMonitor.Hardware;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Zal.Constants.Models;
+using Zal.HelperFunctions.SpecificcomputerDataFunctions;
+using Zal.HelperFunctions.SpecificFunctions;
+using ZalConsole.HelperFunctions;
+using ZalConsole.HelperFunctions.SpecificFunctions;
+
+namespace Zal.HelperFunctions
+{
+ public class computerDataGetter
+ {
+
+ private cpuInfo? cpuInfo;
+ private List? crystalDiskDatas;
+ private List? ramPiecesData;
+ //this variable holds the network speed that the user has chosen as primary.
+ private networkSpeed primarynetworkSpeed = new networkSpeed(download: 0, upload: 0);
+
+ private NetworkSpeedGetter networkSpeedGetter = new NetworkSpeedGetter();
+ //disabled fps feature because it's buggy
+ //public fpsDataGetter fpsDataGetter;
+ //this variable holds the processes and how much % gpu they use. we use this data to determine which process is a game. and get the fps data from it.
+ private Dictionary processesGpuUsage = new Dictionary();
+ private Computer computer = new Computer
+ {
+ IsCpuEnabled = true,
+ IsGpuEnabled = true,
+ IsMemoryEnabled = true,
+ IsMotherboardEnabled = true,
+ IsControllerEnabled = true,
+ IsNetworkEnabled = true,
+ IsStorageEnabled = true
+ };
+ public computerDataGetter()
+ {
+ //fpsDataGetter = new fpsDataGetter(client);
+ uint attempts = 0;
+ while (attempts != 5)
+ {
+ try
+ {
+ computer.Open();
+ break;
+ }
+ catch (Exception ex)
+ {
+ attempts++;
+ }
+ }
+ if (attempts == 5)
+ {
+ Logger.Log("error running computer.open, attempted 5 times and failed");
+ }
+ computer.Accept(new UpdateVisitor());
+
+ //below code is run only once during the lifetime of this program. this is to reduce load.
+ try
+ {
+ cpuInfo = cpuInfoGetter.getcpuInfo();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error getting cpuInfo", ex);
+ }
+ try
+ {
+ ramPiecesData = ramPieceDataGetter.GetRamPiecesData();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error getting ramPiecesData", ex);
+ }
+ try
+ {
+ crystalDiskDatas = CrystaldiskInfoGetter.getcrystalDiskData();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error getting crystalDiskData", ex);
+ }
+
+
+ }
+
+ public async Task getcomputerDataAsync()
+ {
+ computerData computerData = new computerData();
+ computer.Accept(new UpdateVisitor());
+ GlobalClass.Instance.processesGetter.update();
+ computerData.isAdminstrator = IsAdminstratorChecker.IsAdministrator();
+ computerData.taskmanagerData = GlobalClass.Instance.processesGetter.data;
+ if (computer.Hardware.Count == 0)
+ {
+ Logger.Log("warning getting computer data, computerHardware count is 0");
+ }
+ foreach (IHardware hardware in computer.Hardware)
+ {
+ //Console.WriteLine($"name:{hardware.Name},type:{hardware.HardwareType}");
+ var gpuTypes = new HardwareType[] { HardwareType.GpuNvidia, HardwareType.GpuIntel, HardwareType.GpuAmd };
+ if (hardware.HardwareType == HardwareType.Cpu)
+ {
+ try
+ {
+ computerData.cpuData = new cpuData(hardware, cpuInfo);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing cpuData", ex);
+ }
+
+ }
+ else if (hardware.HardwareType.ToString().ToLower().Contains("gpu"))
+ //else if (gpuTypes.Contains(hardware.HardwareType))
+ {
+ try
+ {
+ //Console.WriteLine($"gpu found:{hardware.Name}");
+ var gpu = new gpuData(hardware);
+ computerData.gpuData.Add(gpu);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing gpuData", ex);
+ }
+
+ }
+ else if (hardware.HardwareType == HardwareType.Memory)
+ {
+ try
+ {
+ computerData.ramData = new ramData(hardware, ramPiecesData);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing ramData", ex);
+ }
+
+ }
+ else if (hardware.HardwareType == HardwareType.Motherboard)
+ {
+ try
+ {
+ computerData.motherboardData = new motherboardData(hardware);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing motherboardData", ex);
+ }
+
+ }
+
+ else if (hardware.HardwareType == HardwareType.Storage)
+ {
+ try
+ {
+
+ var storage = new storageData(hardware, crystalDiskDatas);
+ computerData.storagesData.Add(storage);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing storageData", ex, dataToPrint: crystalDiskDatas);
+ }
+
+ }
+ }
+ try
+ {
+ List? monitorsData = monitorDataGetter.getmonitorData();
+ computerData.monitorsData = monitorsData;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing monitorData", ex);
+ }
+ try
+ {
+ batteryData? batteryData = batteryDataGetter.getbatteryData();
+ computerData.batteryData = batteryData;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing batteryData", ex);
+ }
+ try
+ {
+ computerData.processesGpuUsage = processesGpuUsage;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error parsing processesGpuUsage", ex);
+ }
+ try
+ {
+ computerData.primaryNetworkSpeed = networkSpeedGetter.primaryNetworkSpeed;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error getting primary network speed", ex);
+ }
+ try
+ {
+ computerData.networkInterfaces = networkSpeedGetter.networkInterfaceDatas;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError("error getting primary network speed", ex);
+ }
+ return computerData;
+ }
+
+ }
+
+
+}
+class UpdateVisitor : IVisitor
+{
+ public void VisitComputer(IComputer computer)
+ {
+ computer.Traverse(this);
+ }
+ public void VisitHardware(IHardware hardware)
+ {
+ var attempts = 0;
+ while (attempts < 5)
+ {
+ try
+ {
+ hardware.Update();
+ break;
+ }
+ catch
+ {
+ attempts++;
+ }
+ }
+ foreach (IHardware subHardware in hardware.SubHardware) subHardware.Accept(this);
+ }
+ public void VisitSensor(ISensor sensor)
+ {
+ Console.WriteLine(sensor);
+ }
+ public void VisitParameter(IParameter parameter) { }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/FilesGetter.cs b/zal_program/Zal/Backend/HelperFunctions/FilesGetter.cs
new file mode 100644
index 0000000..692587e
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/FilesGetter.cs
@@ -0,0 +1,260 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading;
+
+namespace ZalConsole.HelperFunctions
+{
+ public class FilesGetter
+ {
+ ///used to send file to mobile, this can be used to stop sending the file.
+ CancellationTokenSource cts;
+ int chunkSize = 153600;
+ // SocketIOClient.SocketIO client;
+ //var client;
+ // public FilesGetter(SocketIOClient.SocketIO client) {
+ // this.client = client;
+ // setupListeners();
+ // }
+ // private void setupListeners()
+ // {
+ // client.On("get_directory", async response =>
+ // {
+ // var path = response.GetValue();
+ // if (path == "")
+ // {
+ // var drives = getDrives();
+ // sendData("directory", drives);
+ // return;
+ // }
+ // List folders= [];
+ // try
+ // {
+ // folders = getDirectoryFolders(path);
+ // }
+ // catch(UnauthorizedAccessException) {
+ // await client.EmitAsync("information_text", "Access to path is denied.");
+ // return;
+ // }
+ // var files = getDirectoryFiles(path);
+ // Dictionary data = new Dictionary();
+ // var allFiles = folders.Concat(files).ToList();
+ // sendData("directory", allFiles);
+ //
+ //
+ //
+ // });
+ //
+ // client.On("get_file", async response =>
+ // {
+ // var path = response.GetValue();
+ // cts = new CancellationTokenSource();
+ //
+ // List sentChunks = [];
+ //
+ // using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
+ // {
+ // byte[] buffer = new byte[chunkSize];
+ // int bytesRead;
+ // long byteOffset = 0;
+ //
+ // while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) > 0)
+ // {
+ // // Convert the chunk to base64 or any other encoding as needed
+ // string base64Chunk = Convert.ToBase64String(buffer, 0, bytesRead);
+ // // Send the chunk with byte offset to Flutter using the sendData function
+ // sendData("file", new { ByteOffset = byteOffset, ChunkData = base64Chunk });
+ // sentChunks.Add(byteOffset);
+ // // Update the byte offset for the next chunk
+ // byteOffset += bytesRead;
+ // // Simulate some delay to avoid overwhelming the network
+ // await Task.Delay(150);
+ //
+ // }
+ //
+ // }
+ // await Task.Delay(2000);
+ // sendData("file_complete", new { chunkSize = chunkSize, sentChunks = sentChunks });
+ //
+ // });
+ // client.On("get_file_missing_chunks", async response =>
+ // {
+ // var data = response.GetValue();
+ // var parsedData = JsonConvert.DeserializeObject>(data);
+ // var path = parsedData["path"];
+ // foreach(var chunk in parsedData["chunks"])
+ // {
+ // using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
+ // {
+ // byte[] buffer = new byte[chunkSize];
+ // var bytesRead = fs.Read(buffer, 0, buffer.Length);
+ // string base64Chunk = Convert.ToBase64String(buffer, 0, bytesRead);
+ // sendData("file", new { ByteOffset = chunk, ChunkData = base64Chunk });
+ // await Task.Delay(150);
+ //
+ // }
+ // }
+ // await Task.Delay(150);
+ // sendData("file_complete", new { chunkSize = chunkSize, sentChunks = parsedData["chunks"] });
+ //
+ //
+ //
+ // });
+ // client.On("run_file", async response =>
+ // {
+ // var data = response.GetValue();
+ // try
+ // {
+ // System.Diagnostics.Process.Start(data);
+ // await client.EmitAsync("information_text", "file ran!");
+ //
+ // }catch (Exception ex)
+ // {
+ // await client.EmitAsync("information_text", $"error running file: {ex.Message}");
+ // }
+ //
+ //
+ // });
+ // client.On("move_file", async response =>
+ // {
+ // var data = response.GetValue();
+ // var parsedData = JsonConvert.DeserializeObject>(data);
+ // try
+ // {
+ // System.IO.File.Move(parsedData["oldPath"], parsedData["newPath"]);
+ // await client.EmitAsync("information_text", $"done!");
+ // }
+ // catch (Exception ex)
+ // {
+ // await client.EmitAsync("information_text", $"error performing action: {ex.Message}");
+ // }
+ // });
+ // client.On("copy_file", async response =>
+ // {
+ // var data = response.GetValue();
+ // var parsedData = JsonConvert.DeserializeObject>(data);
+ // try
+ // {
+ // System.IO.File.Copy(parsedData["oldPath"], parsedData["newPath"]);
+ // await client.EmitAsync("information_text", $"done!");
+ // }
+ // catch (Exception ex)
+ // {
+ // await client.EmitAsync("information_text", $"error performing action: {ex.Message}");
+ // }
+ // });
+ // client.On("delete_file", async response =>
+ // {
+ // var data = response.GetValue();
+ // try
+ // {
+ // System.IO.File.Delete(data);
+ // await client.EmitAsync("information_text", $"done!");
+ // }
+ // catch (Exception ex)
+ // {
+ // await client.EmitAsync("information_text", $"error performing action: {ex.Message}");
+ // }
+ //
+ // });
+ // }
+ //void ProcessChunk(byte[] chunk, int bytesRead)
+ //{
+ // Dictionary data = new Dictionary();
+ // data["chunk"] = Convert.ToBase64String(chunk);
+ // data["bytesRead"]= bytesRead;
+ // sendData("file", data);
+ //}
+ // public void ProcessReceivedChunk(byte[] chunk, long byteLocation, long remainingBytes)
+ //{
+ // Dictionary data= new Dictionary();
+ // data["chunk"] = chunk;
+ // data["byteLocation"]=byteLocation;
+ // data["remainingBytes"]=remainingBytes;
+ //
+ // sendData("file",data);
+ //}
+ private List getDirectoryFiles(string path)
+ {
+ var result = new List();
+ DirectoryInfo info = new DirectoryInfo(path);
+ if (info.Exists)
+ {
+
+ var files = info.GetFiles();
+ foreach (var file in files)
+ {
+ if (file.Attributes.HasFlag(FileAttributes.Hidden))
+ {
+ continue;
+ }
+ FileData filed = new FileData();
+ filed.name = file.Name;
+ filed.extension = file.Extension;
+ filed.directory = file.DirectoryName;
+ filed.fileType = "file";
+ filed.size = file.Length;
+ filed.dateModified = ConvertToUnixTimestamp(file.LastWriteTime);
+ filed.dateCreated = ConvertToUnixTimestamp(file.CreationTime);
+ result.Add(filed);
+
+ }
+ }
+ return result;
+ }
+ private List getDirectoryFolders(string path)
+ {
+ var result = new List();
+ DirectoryInfo info = new DirectoryInfo(path);
+ if (info.Exists)
+ {
+
+ var directories = info.GetDirectories();
+ foreach (var directory in directories)
+ {
+ if (directory.Attributes.HasFlag(FileAttributes.Hidden))
+ {
+ continue;
+ }
+ FileData folder = new FileData();
+ folder.directory = path;
+ folder.name = directory.Name;
+ folder.fileType = "folder";
+ folder.dateCreated = ConvertToUnixTimestamp(directory.CreationTime);
+ folder.dateModified = ConvertToUnixTimestamp(directory.LastWriteTime);
+ result.Add(folder);
+
+ }
+ }
+ return result;
+ }
+ public static long ConvertToUnixTimestamp(DateTime date)
+ {
+ DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+ TimeSpan diff = date.ToUniversalTime() - origin;
+ return ((long)diff.TotalMilliseconds);
+ }
+ private List getDrives()
+ {
+ DriveInfo[] drives = DriveInfo.GetDrives();
+ List result = new List();
+ foreach (var drive in drives)
+ {
+ FileData data = new FileData();
+ data.label = drive.VolumeLabel;
+ data.name = drive.Name;
+ data.fileType = "folder";
+ data.size = drive.TotalSize - drive.AvailableFreeSpace;
+ result.Add(data);
+
+ }
+ return result;
+ }
+
+ // private async void sendData(string key,object data)
+ // {
+ // var serializedData = Newtonsoft.Json.JsonConvert.SerializeObject(data);
+ // await client.EmitAsync(key, serializedData);
+ // }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/FpsDataGetter.cs b/zal_program/Zal/Backend/HelperFunctions/FpsDataGetter.cs
new file mode 100644
index 0000000..5b0a64a
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/FpsDataGetter.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using ZalConsole.HelperFunctions;
+
+namespace Zal.HelperFunctions
+{
+ public class FpsDataGetter
+ {
+ private Process? presentmonProcess;
+ private System.Threading.Tasks.Task fpsTask;
+ private bool isDisposed = false;
+ public event EventHandler sendFpsData;
+ private List fpsDatas = [];
+ private int processId;
+ Stopwatch stopwatch = new Stopwatch();
+ private List lastSecondFpsDatas = [];
+ public FpsDataGetter()
+ {
+ stopwatch.Start();
+ //run presentmon and refresh every 30 secs to avoid memory leak.
+ //presentmonTimer = new Timer(_ =>
+ // {
+ // Call your method directly inside the timer
+ // startPresentmon();
+ // }, null, 0, 30000);
+
+ //send fpsdata to mobile every n seconds
+
+ }
+
+ public double calculatePercentile(IEnumerable seq, double percentile)
+ {
+ var elements = seq.ToArray();
+ Array.Sort(elements);
+ double realIndex = percentile * (elements.Length - 1);
+ int index = (int)realIndex;
+ double frac = realIndex - index;
+ if (index + 1 < elements.Length)
+ return elements[index] * (1 - frac) + elements[index + 1] * frac;
+ else
+ return elements[index];
+ }
+ public void disposeIt()
+ {
+ isDisposed = true;
+ stopPresentmon();
+ }
+ public void stopPresentmon()
+ {
+ foreach (var process in Process.GetProcessesByName("presentmon"))
+ {
+ process.Kill();
+ }
+ }
+ public async void startPresentmon(int processId)
+ {
+
+ //startFpsTimer();
+ //kill any presentmon process that might be running
+ var filePath = GlobalClass.Instance.getFilepathFromResources("presentmon.exe");
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = filePath,
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ Arguments = $"-output_stdout -stop_existing_session -process_id {processId} -terminate_on_proc_exit",
+ };
+ presentmonProcess = new Process { StartInfo = startInfo };
+ try
+ {
+
+ presentmonProcess.Start();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"error running presentmon", ex);
+ }
+ Task.Run(async () => { await parseIncomingPresentmonData(); });
+ }
+ private static String getTimestamp()
+ {
+
+ return (new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds()).ToString();
+ }
+ //chosenProcessName is the process that was used during the creation of this void, if the currentProcessName changes, this void will stop itself.
+ private async Task parseIncomingPresentmonData()
+ {
+ StreamReader reader = presentmonProcess.StandardOutput;
+
+ while (!reader.EndOfStream)
+ {
+ if (isDisposed) break;
+ //Thread.Sleep(30);
+ string line = reader.ReadLine();
+ var msBetweenPresents = "";
+ try
+ {
+ msBetweenPresents = line.Split(',')[9];
+ }
+ catch
+ {
+ continue;
+ }
+
+ uint? processId = null;
+ String? processName = line.Split(',')[0];
+ try
+ {
+ processId = uint.Parse(line.Split(',')[1]);
+ }
+ catch
+ {
+
+ }
+ if (processName == "") continue;
+
+ if (processId != null)
+ {
+ var time = getTimestamp();
+ if (msBetweenPresents.Any(char.IsDigit))
+ {
+ var doubledMsBetweenPresents = double.Parse(msBetweenPresents);
+ fpsDatas.Add((1000 / doubledMsBetweenPresents));
+
+
+ if (fpsDatas.Count > 10)
+ {
+ try
+ {
+ sendFpsData.Invoke(null, fpsDatas);
+ }
+ catch
+ {
+
+ }
+ fpsDatas.Clear();
+ }
+ continue;
+ lastSecondFpsDatas.Add((1000 / doubledMsBetweenPresents));
+ if (stopwatch.ElapsedMilliseconds > 100)
+ {
+
+ }
+
+ //lastSecondFpsDatas.Add((1000 / doubledMsBetweenPresents));
+ if (stopwatch.ElapsedMilliseconds > 100)
+ {
+ try
+ {
+
+ System.Diagnostics.Debug.WriteLine($"p: {processId} - {processName}");
+ List copyOfFpsDatas = fpsDatas.ToList();
+ var percentile01 = calculatePercentile(copyOfFpsDatas, 0.01);
+ var percentile001 = calculatePercentile(copyOfFpsDatas, 0.001);
+ var averageFps = copyOfFpsDatas.Average();
+ var dataToSend = new Dictionary();
+ dataToSend["percentile01"] = percentile01;
+ dataToSend["percentile001"] = percentile001;
+ dataToSend["averageFps"] = averageFps;
+ dataToSend["currentFps"] = lastSecondFpsDatas.Average();
+ //dataToSend["data"] = copyOfFpsDatas;
+ sendFpsData.Invoke(null, dataToSend);
+
+ lastSecondFpsDatas.Clear();
+ GC.Collect(GC.GetGeneration(lastSecondFpsDatas), GCCollectionMode.Forced);
+ if (fpsDatas.Count > 500)
+ {
+ fpsDatas.RemoveAt(0);
+
+ }
+ stopwatch.Restart();
+ }
+ catch
+ {
+
+ }
+
+ }
+
+
+ }
+ }
+ }
+
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/GlobalClass.cs b/zal_program/Zal/Backend/HelperFunctions/GlobalClass.cs
new file mode 100644
index 0000000..54532bc
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/GlobalClass.cs
@@ -0,0 +1,233 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Management;
+using System.Threading.Tasks;
+using Zal;
+using Zal.HelperFunctions;
+using ZalConsole.Constants.Models;
+
+namespace ZalConsole.HelperFunctions
+{
+ public class GlobalClass
+ {
+ private ManagementObjectCollection? win32DiskDrives;
+ private ManagementObjectCollection? win32DiskPartitions;
+ private ManagementObjectCollection? win32DiskPartitionsForFreeDiskSpace;
+ public ProcessesGetter processesGetter = new ProcessesGetter();
+ private static GlobalClass instance;
+ private List? processInfos;
+ private GlobalClass()
+ {
+ // Initialization code here
+ }
+ public bool saveTextToDocumentFolder(string filename, string data)
+ {
+ var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Zal");
+ Directory.CreateDirectory(directory);
+ var filePath = Path.Combine(directory, filename);
+ try
+ {
+
+ using (StreamWriter writer = new StreamWriter(filePath))
+ {
+ writer.Write(data);
+ }
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"error writing to {filePath}", ex);
+ return false;
+ }
+ }
+ public async Task readTextFromDocumentFolder(string filename)
+ {
+ var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Zal");
+ var filePath = Path.Combine(directory, filename);
+
+ try
+ {
+ if (!File.Exists(filePath))
+ {
+ // Create the directory if it doesn't exist
+ Directory.CreateDirectory(directory);
+
+ // Create the file
+ File.Create(filePath).Close(); // Close the file stream immediately after creating it
+ }
+
+ using (StreamReader reader = new StreamReader(filePath))
+ {
+ var data = await reader.ReadToEndAsync();
+ return data;
+ }
+ }
+ catch (FileNotFoundException)
+ {
+ // File not found
+ return null;
+ }
+ catch (IOException c)
+ {
+ // Error reading file, try to delete the file
+ try
+ {
+ File.Delete(filePath);
+ }
+ catch (Exception e)
+ {
+ Logger.LogError($"failed to read {filePath} and failed to delete it", e);
+ }
+ return null;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // Access denied
+ return null;
+ }
+ catch (Exception)
+ {
+ // Any other unexpected error
+ return null;
+ }
+ }
+ public static GlobalClass Instance
+ {
+ get
+ {
+ if (instance == null)
+ {
+ instance = new GlobalClass();
+ }
+ return instance;
+ }
+ }
+ public string getFilepathFromResources(String fileName)
+ {
+ return Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Resources", fileName);
+ }
+ public string extractZipFromResourcesAndGetFilepathWithinTheExtract(String zipFileName, String filenameWithinTheExtract)
+ {
+ var zipFilepath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Resources", zipFileName);
+ var zipFileNameWithoutDotZip = zipFilepath.Replace(".zip", "");
+ try
+ {
+ System.IO.Compression.ZipFile.ExtractToDirectory(zipFilepath, zipFileNameWithoutDotZip);
+ }
+ catch (IOException c)
+ {
+
+ }
+ catch (Exception c)
+ {
+ Logger.LogError("failed to extract zip from resources folder", c);
+ }
+ return Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Resources", zipFileNameWithoutDotZip, filenameWithinTheExtract);
+ }
+
+ ///return icon of a file in base64
+ public string getFileIcon(String fileName)
+ {
+ var filePath = extractZipFromResourcesAndGetFilepathWithinTheExtract("get_process_icon.zip", "get_process_icon.exe");
+
+ Process process = new Process();
+ process.StartInfo.FileName = filePath;
+ process.StartInfo.Arguments = $"\"{fileName}\"";
+ process.StartInfo.UseShellExecute = false;
+ process.StartInfo.RedirectStandardOutput = true;
+ process.StartInfo.RedirectStandardError = true;
+ process.StartInfo.CreateNoWindow = true;
+ process.Start();
+ //* Read the output (or the error)
+ string output = process.StandardOutput.ReadToEnd();
+ process.WaitForExit();
+ output = output.Replace("\r\n", "");
+ return output;
+ }
+
+ public ManagementObjectCollection getWin32DiskDrives()
+ {
+ if (win32DiskDrives == null)
+ {
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
+ win32DiskDrives = searcher.Get();
+ Task.Run(async () =>
+ {
+ await Task.Delay(TimeSpan.FromSeconds(60));
+ win32DiskDrives = null;
+ });
+ }
+ return win32DiskDrives;
+
+
+ }
+ public List getProcessInfos()
+ {
+ if (processInfos == null)
+ {
+ string jsonFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources\\Processes.json");
+
+ // Check if the file exists
+ if (File.Exists(jsonFilePath))
+ {
+ // Read the contents of the JSON file
+ string jsonContent = File.ReadAllText(jsonFilePath);
+ processInfos = Newtonsoft.Json.JsonConvert.DeserializeObject>(jsonContent);
+ }
+ }
+ return processInfos;
+
+ }
+ public List getWin32DiskPartitions(int diskNumber)
+ {
+ if (win32DiskPartitions == null)
+ {
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskPartition");
+ win32DiskPartitions = searcher.Get();
+ Task.Run(async () =>
+ {
+ await Task.Delay(TimeSpan.FromSeconds(60));
+ win32DiskPartitions = null;
+ });
+ }
+
+ // Filter the partitions based on the specified disk number
+ List filteredPartitions = new List();
+ foreach (ManagementObject partition in win32DiskPartitions)
+ {
+ // Adjust the property name based on the actual property for the disk number
+ int currentDiskNumber = Convert.ToInt32(partition["DiskIndex"]);
+
+ if (currentDiskNumber == diskNumber)
+ {
+ filteredPartitions.Add(partition);
+ }
+ }
+
+ return filteredPartitions;
+ }
+ public ManagementObjectCollection getWin32DiskPartitionsForFreeDiskSpace()
+ {
+ if (win32DiskPartitionsForFreeDiskSpace == null)
+ {
+ ManagementScope scope = new ManagementScope(@"\\.\root\cimv2");
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
+ scope.Connect();
+ searcher.Scope = scope;
+ win32DiskPartitionsForFreeDiskSpace = searcher.Get();
+
+ Task.Run(async () =>
+ {
+ await Task.Delay(TimeSpan.FromSeconds(60));
+ win32DiskPartitionsForFreeDiskSpace = null;
+ });
+ }
+ return win32DiskPartitionsForFreeDiskSpace;
+
+
+ }
+ }
+
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/Logger.cs b/zal_program/Zal/Backend/HelperFunctions/Logger.cs
new file mode 100644
index 0000000..f0a79a8
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/Logger.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal
+{
+ public static class Logger
+ {
+ static readonly object _locker = new object();
+ public static void LogError(string message, Exception ex, Object dataToPrint = null)
+ {
+ string stringifiedData = Newtonsoft.Json.JsonConvert.SerializeObject(dataToPrint);
+ string text = dataToPrint == null ? "" : stringifiedData;
+ Logger.Log($"{message},,error:{ex.Message},,stack:{ex.StackTrace},,{text}");
+ }
+ public static void Log(string logMessage)
+ {
+ try
+ {
+ var logFilePath = GetLogFilePath();
+ //Use this for daily log files : "Log" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
+ WriteToLog(logMessage, logFilePath);
+ }
+ catch (Exception e)
+ {
+ //the irony, right? well i can't do much here
+ }
+ }
+ public static String GetLogFilePath()
+ {
+ return Path.Combine(Path.GetTempPath(), "zal_log.txt");
+
+ }
+ public static void ResetLog()
+ {
+ try
+ {
+ var logFilePath = GetLogFilePath();
+ var lines = File.ReadAllLines(logFilePath);
+ File.WriteAllLines(logFilePath, []);
+ }
+ catch
+ {
+
+ }
+
+ }
+
+ static void WriteToLog(string logMessage, string logFilePath)
+ {
+ lock (_locker)
+ {
+ string formattedDate = DateTime.Now.ToString("dd/MM/yyyy - HH:mm:ss");
+ File.AppendAllText(logFilePath,
+ string.Format("Date: {1}{0}Msg: {2}{0}--------------------{0}",
+ Environment.NewLine, formattedDate, logMessage));
+ }
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/ProcessesGetter.cs b/zal_program/Zal/Backend/HelperFunctions/ProcessesGetter.cs
new file mode 100644
index 0000000..44daefd
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/ProcessesGetter.cs
@@ -0,0 +1,109 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Zal.HelperFunctions
+{
+ public class ProcessesGetter
+ {
+ SocketIOClient.SocketIO client = new SocketIOClient.SocketIO($"http://localhost:6511/");
+ private Dictionary> taskCompletionSources = new Dictionary>();
+ public Dictionary data = new Dictionary();
+
+ //this list contains the names of processes that we've already loaded and sent to the phone.
+ //this is to save network bandwidth as icons are quite large (i think about 5-10kb each),
+ //so we cache the icons in the mobile app, and when the app disconnects, we reset this list
+ //so that we send icons to the app once again when app reconnects.
+ private List loadedIcons = new List();
+ public ProcessesGetter()
+ {
+ client.On("process_icon", async response =>
+ {
+ var data = response.GetValue>();
+ var process = data["process"];
+ var icon = data["icon"];
+ if (taskCompletionSources.TryGetValue(process, out var tcs))
+ {
+ tcs.SetResult(icon);
+ taskCompletionSources.Remove(process);
+ }
+ });
+ client.ConnectAsync();
+ }
+ public void resetSentIcons()
+ {
+ loadedIcons.Clear();
+ }
+ public async Task getFileIcon(string filepath)
+ {
+ var tcs = new TaskCompletionSource();
+ taskCompletionSources[filepath] = tcs;
+ client.EmitAsync("get_process_icon", filepath);
+ var timeoutTask = Task.Delay(2000); // Timeout after 2 seconds
+ var completedTask = await Task.WhenAny(tcs.Task, timeoutTask);
+
+ if (completedTask == timeoutTask)
+ {
+ // Timeout occurred
+ return null;
+ }
+ else
+ {
+ return await tcs.Task;
+ }
+ }
+ public async Task update()
+ {
+ Dictionary result = new Dictionary();
+ var allProcesses = Process.GetProcesses();
+ foreach (var process in allProcesses)
+ {
+ string processName = process.ProcessName;
+ long ramUsageBytes = process.WorkingSet64;
+ Dictionary processData = new Dictionary();
+ if (result.ContainsKey(processName))
+ {
+ processData = (Dictionary)result[processName];
+ processData["memoryUsage"] = (long)processData["memoryUsage"] + ramUsageBytes / (1024 * 1024);
+ processData["pids"] = ((List)processData["pids"]).Concat(new[] { (int)process.Id }).ToList();
+ result[processName] = processData;
+ }
+ else
+ {
+ processData["memoryUsage"] = (long)ramUsageBytes / (1024 * 1024);
+ processData["pids"] = new List { process.Id };
+ processData["cpuPercent"] = 0.0;
+
+ //get the process icon
+ try
+ {
+ //i've disabled icon loading until further insight.
+ //when the app connects to this program, we have to confidently reset the loadedIcons variable to make sure
+ //the app receives the process icons.
+ if (false)
+ //if (loadedIcons.Contains(processName) == false)
+ {
+ var filepath = process.MainModule.FileName;
+ var icon = await getFileIcon(filepath);
+ if (icon != null)
+ {
+ processData["icon"] = icon;
+ loadedIcons.Add(processName);
+ }
+
+ }
+ }
+ catch (Exception c)
+ {
+ // loadedIcons.Add(processName);
+ }
+ result[processName] = processData;
+ }
+ }
+ data = result;
+ }
+
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/RunningProgramsTracker.cs b/zal_program/Zal/Backend/HelperFunctions/RunningProgramsTracker.cs
new file mode 100644
index 0000000..45dbeb0
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/RunningProgramsTracker.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using Zal.Functions.MajorFunctions;
+using Zal.HelperFunctions.SpecificFunctions;
+using ZalConsole.HelperFunctions.SpecificFunctions;
+
+namespace ZalConsole.HelperFunctions
+{
+ public class RunningProgramsTracker
+ {
+ private Timer timer1;
+ private List runningProcesses = [];
+ public RunningProgramsTracker()
+ {
+ runAsync();
+ }
+ private async Task runAsync()
+ {
+ while (true)
+ {
+ //wait for 5 mintues
+ await Task.Delay(300000);
+ try
+ {
+ //this list contains the processes that has kept running in the last [interval] seconds, we send them to the database.
+ var processesThatStillRunning = new List();
+ var currentRunningProcesses = getRunningProcesses();
+ //check which processes are still running
+ foreach (var currentRunningProcess in currentRunningProcesses)
+ {
+ if (runningProcesses.Contains(currentRunningProcess))
+ {
+ processesThatStillRunning.Add(currentRunningProcess);
+ }
+ else
+ {
+ //if the list doesn't contain this process, that means this process is new, let's add it.
+ runningProcesses.Add(currentRunningProcess);
+ }
+ }
+ //remove the processes
+ foreach (var runningProcess in runningProcesses)
+ {
+ if (!currentRunningProcesses.Contains(runningProcess))
+ {
+ try
+ {
+ runningProcess.Remove(currentRunningProcesses.IndexOf(runningProcess));
+ }
+ catch { }
+ }
+ }
+ if (processesThatStillRunning.Count != 0)
+ {
+ var response = await ApiManager.SendDataToDatabase("program-times", new Dictionary() {
+ {"programs",processesThatStillRunning }
+});
+ Console.WriteLine(response);
+
+
+
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.ToString());
+ }
+
+ }
+ }
+ private string loadJson()
+ {
+ var directory = getJsonPath();
+ using (StreamReader fs = File.OpenText(Path.Combine(directory, "processes.json")))
+ {
+ return fs.ReadToEnd();
+ }
+ }
+ private string getJsonPath()
+ {
+ var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Zal");
+ Directory.CreateDirectory(directory);
+ return directory;
+ }
+ private List getRunningProcesses()
+ {
+ List result = new List();
+ Process[] processes = Process.GetProcesses();
+ // Iterate through each process
+ var gpuProcesses = GpuUtilizationGetter.getProcessesGpuUsage(skipBlackListedProcesses: false);
+ var processInfos = GlobalClass.Instance.getProcessInfos();
+ foreach (var gpuProcess in gpuProcesses)
+ {
+ result.Add(gpuProcess.Value["name"]);
+ }
+ foreach (Process process in processes)
+ {
+ // Check if the process has a main window title
+ if (!string.IsNullOrEmpty(process.MainWindowTitle))
+ {
+ try
+ {
+ FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(process.MainModule.FileName);
+ string fileDescription = fileVersionInfo.FileDescription;
+ if (fileDescription == "") continue;
+ var foundProcessInfo = processInfos.Where((a) => a.name == fileDescription).ToList().FirstOrDefault();
+ if (foundProcessInfo != null && foundProcessInfo.isBlacklisted)
+ {
+ continue;
+ }
+ ProcesspathGetter.save(fileDescription, process.MainModule.FileName);
+ result.Add(fileDescription);
+ }
+ catch
+ {
+ continue;
+ }
+
+ }
+ }
+ return result;
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/ScreenCapturer.cs b/zal_program/Zal/Backend/HelperFunctions/ScreenCapturer.cs
new file mode 100644
index 0000000..1eb99d7
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/ScreenCapturer.cs
@@ -0,0 +1,146 @@
+using SharpDX.Direct3D11;
+using SharpDX.DXGI;
+using SharpDX;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing.Imaging;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ZalConsole.HelperFunctions
+{
+
+ public class ScreenCapturer
+ {
+ private byte[] _previousScreen;
+ private bool _run, _init;
+ public int Size { get; private set; }
+ public ScreenCapturer()
+ {
+
+ }
+
+ public void Start(int frameRate = 30)
+ {
+ _run = true;
+ var factory = new Factory1();
+ //Get first adapter
+ var adapter = factory.GetAdapter1(0);
+ //Get device from adapter
+ var device = new SharpDX.Direct3D11.Device(adapter);
+ //Get front buffer of the adapter
+ var output = adapter.GetOutput(0);
+ var output1 = output.QueryInterface();
+
+ // Width/Height of desktop to capture
+ int width = output.Description.DesktopBounds.Right;
+ int height = output.Description.DesktopBounds.Bottom;
+
+
+ // Create Staging texture CPU-accessible
+ var textureDesc = new Texture2DDescription
+ {
+ CpuAccessFlags = CpuAccessFlags.Read,
+ BindFlags = BindFlags.None,
+ Format = Format.B8G8R8A8_UNorm,
+ Width = width,
+ Height = height,
+ OptionFlags = ResourceOptionFlags.None,
+ MipLevels = 1,
+ ArraySize = 1,
+ SampleDescription = { Count = 1, Quality = 0 },
+ Usage = ResourceUsage.Staging
+ };
+ var screenTexture = new Texture2D(device, textureDesc);
+
+ Task.Factory.StartNew(() =>
+ {
+ // Duplicate the output
+ using (var duplicatedOutput = output1.DuplicateOutput(device))
+ {
+ while (_run)
+ {
+ try
+ {
+ SharpDX.DXGI.Resource screenResource;
+ OutputDuplicateFrameInformation duplicateFrameInformation;
+
+ // Try to get duplicated frame within given time is ms
+ duplicatedOutput.TryAcquireNextFrame(1000, out duplicateFrameInformation, out screenResource);
+
+ // copy resource into memory that can be accessed by the CPU
+ using (var screenTexture2D = screenResource.QueryInterface())
+ device.ImmediateContext.CopyResource(screenTexture2D, screenTexture);
+
+ // Get the desktop capture texture
+ var mapSource = device.ImmediateContext.MapSubresource(screenTexture, 0, MapMode.Read, SharpDX.Direct3D11.MapFlags.None);
+
+ // Create Drawing.Bitmap
+ using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb))
+ {
+ var boundsRect = new Rectangle(0, 0, width, height);
+
+ // Copy pixels from screen capture Texture to GDI bitmap
+ var mapDest = bitmap.LockBits(boundsRect, ImageLockMode.WriteOnly, bitmap.PixelFormat);
+ var sourcePtr = mapSource.DataPointer;
+ var destPtr = mapDest.Scan0;
+ for (int y = 0; y < height; y++)
+ {
+ // Copy a single line
+ Utilities.CopyMemory(destPtr, sourcePtr, width * 4);
+
+ // Advance pointers
+ sourcePtr = IntPtr.Add(sourcePtr, mapSource.RowPitch);
+ destPtr = IntPtr.Add(destPtr, mapDest.Stride);
+ }
+
+ // Release source and dest locks
+ bitmap.UnlockBits(mapDest);
+ device.ImmediateContext.UnmapSubresource(screenTexture, 0);
+
+ //using (var ms = new MemoryStream())
+ // {
+ // bitmap.Save(ms, ImageFormat.Bmp);
+
+
+ // ScreenRefreshed?.Invoke(this, ms.ToArray());
+ // _init = true;
+ // }
+ ScreenRefreshed?.Invoke(this, bitmap);
+ _init = true;
+ }
+ screenResource.Dispose();
+ duplicatedOutput.ReleaseFrame();
+ Thread.Sleep(1000 / frameRate);
+ }
+ catch (SharpDXException e)
+ {
+ if (e.ResultCode.Code != SharpDX.DXGI.ResultCode.WaitTimeout.Result.Code)
+ {
+ Trace.TraceError(e.Message);
+ Trace.TraceError(e.StackTrace);
+ }
+ }
+ catch
+ {
+
+ }
+ }
+ }
+ });
+ while (!_init) ;
+ }
+
+ public void Stop()
+ {
+ _run = false;
+ }
+
+ public EventHandler ScreenRefreshed;
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/BatteryDataGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/BatteryDataGetter.cs
new file mode 100644
index 0000000..8072f5b
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/BatteryDataGetter.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Zal.Constants.Models;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class batteryDataGetter
+ {
+ public static batteryData getbatteryData()
+ {
+ PowerStatus p = System.Windows.Forms.SystemInformation.PowerStatus;
+
+ int life = (int)(p.BatteryLifePercent * 100);
+
+ var data = new batteryData();
+ data.hasBattery = p.BatteryChargeStatus != BatteryChargeStatus.NoSystemBattery;
+ data.life = (uint)life;
+ data.isCharging = p.PowerLineStatus == System.Windows.Forms.PowerLineStatus.Online;
+ data.lifeRemaining = (uint)p.BatteryLifeRemaining;
+
+ return data;
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CpuInfoGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CpuInfoGetter.cs
new file mode 100644
index 0000000..23fdb23
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CpuInfoGetter.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management;
+using System.Text;
+using System.Threading.Tasks;
+using Zal.Constants.Models;
+
+namespace Zal.HelperFunctions.SpecificcomputerDataFunctions
+{
+ class cpuInfoGetter
+ {
+ public static cpuInfo getcpuInfo()
+ {
+
+ var cpu =
+ new ManagementObjectSearcher("select * from Win32_Processor")
+ .Get()
+ .Cast()
+ .First();
+ cpuInfo cpuInfo = new cpuInfo();
+ cpuInfo.socket = (string)cpu["SocketDesignation"];
+ cpuInfo.name = (string)cpu["Name"];
+ cpuInfo.speed = (uint)cpu["MaxClockSpeed"];
+ cpuInfo.busSpeed = (uint)cpu["ExtClock"];
+ cpuInfo.l2Cache = (uint)cpu["L2CacheSize"] * (ulong)1024;
+ cpuInfo.l3Cache = (uint)cpu["L3CacheSize"] * (ulong)1024;
+ cpuInfo.cores = (uint)cpu["NumberOfCores"];
+ cpuInfo.threads = (uint)cpu["NumberOfLogicalProcessors"];
+
+ cpuInfo.name =
+ cpuInfo.name
+ .Replace("(TM)", "™")
+ .Replace("(tm)", "™")
+ .Replace("(R)", "®")
+ .Replace("(r)", "®")
+ .Replace("(C)", "©")
+ .Replace("(c)", "©")
+ .Replace(" ", " ")
+ .Replace(" ", " ");
+ return cpuInfo;
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CrystalDiskInfoGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CrystalDiskInfoGetter.cs
new file mode 100644
index 0000000..467be30
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/CrystalDiskInfoGetter.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Zal.Constants.Models;
+using ZalConsole.HelperFunctions;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class CrystaldiskInfoGetter
+ {
+ static public List? getcrystalDiskData()
+ {
+ if (IsAdminstratorChecker.IsAdministrator() == false)
+ {
+ //dont run if it's not running as adminstrator, because crystaldiskInfo don't work without it
+ Logger.Log("didn't run crystaldiskInfo, program isn't running as adminstrator");
+ return null;
+ }
+ var filePath = GlobalClass.Instance.extractZipFromResourcesAndGetFilepathWithinTheExtract("DiskInfo.zip", "diskInfo.exe");
+
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = filePath,
+ RedirectStandardOutput = true,
+ UseShellExecute = false,
+ CreateNoWindow = true,
+ Arguments = "/CopyExit diskInfo.txt",
+ };
+ var process = new Process { StartInfo = startInfo };
+
+ try
+ {
+ process.Start();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"error running crystaldiskInfo process", ex);
+ }
+ try
+ {
+ process.WaitForExit();
+ string resultPath = Path.Combine(System.IO.Path.GetDirectoryName(filePath), "diskInfo.txt");
+ var diskInfos = CrystaldiskInfoGetter.parseCrystaldiskInfoOutput(resultPath);
+ process.Close();
+ return diskInfos;
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"error parsing crystaldiskInfo data", ex);
+ }
+ return null;
+
+
+ }
+
+
+ static private List parseCrystaldiskInfoOutput(String filePath)
+ {
+
+ List hardwareList = new List();
+ crystalDiskData currentHardware = null;
+
+ foreach (string line in File.ReadLines(filePath))
+ {
+ if (line.StartsWith(" (0"))
+ {
+ // New hardware entry found
+ if (currentHardware != null)
+ {
+ hardwareList.Add(currentHardware);
+
+
+ }
+
+ currentHardware = new crystalDiskData();
+ currentHardware.info = new Dictionary();
+ }
+ else if (currentHardware != null)
+ {
+ if (line.Contains("Model :"))
+ {
+ currentHardware.info.Add("model", line.Split(':')[1].Trim());
+ }
+ if (line.Contains("Buffer Size :") && line.Contains("Unknown") == false)
+ {
+ string hoursString = Regex.Match(line.Split(':')[1].Trim(), @"\d+").Value;
+ if (!string.IsNullOrEmpty(hoursString))
+ {
+ currentHardware.info.Add("bufferSize", int.Parse(hoursString));
+ }
+ }
+ if (line.Contains("Transfer Mode :"))
+ {
+ string text = line.Split(':')[1];
+
+ currentHardware.info.Add("transferMode", text.Split('|'));
+
+ }
+ if (line.Contains("Queue Depth :"))
+ {
+ currentHardware.info.Add("queueDepth", line.Split(':')[1].Trim());
+ }
+ if (line.Contains("# Of Sectors :"))
+ {
+ currentHardware.info.Add("sectors", line.Split(':')[1].Trim());
+ }
+ if (line.Contains("Power On Hours :"))
+ {
+ string hoursString = Regex.Match(line.Split(':')[1].Trim(), @"\d+").Value;
+ if (!string.IsNullOrEmpty(hoursString))
+ {
+ currentHardware.info.Add("powerOnHours", int.Parse(hoursString));
+ }
+ }
+ if (line.Contains("Drive Letter :"))
+ {
+ List driveLetters = ParseDriveLettersFromString(line);
+ if (driveLetters.Count != 0)
+ {
+ currentHardware.info.Add("driveLetters", driveLetters);
+ }
+ }
+ if (line.Contains("Power On Count :"))
+ {
+ string hoursString = Regex.Match(line.Split(':')[1].Trim(), @"\d+").Value;
+ if (!string.IsNullOrEmpty(hoursString))
+ {
+ currentHardware.info.Add("powerOnCount", int.Parse(hoursString));
+ }
+ }
+ if (line.Contains("Health Status :"))
+ {
+ string hoursString = Regex.Match(line.Split(':')[1].Trim(), @"\d+").Value;
+ if (!string.IsNullOrEmpty(hoursString))
+ {
+ currentHardware.info.Add("healthPercentage", int.Parse(hoursString));
+ }
+
+ Regex regex = new Regex("[a-zA-Z]+");
+ Match match = regex.Match(line.Split(':')[1].Trim());
+ if (match.Success)
+ {
+ currentHardware.info.Add("healthText", match.Value);
+ }
+ }
+ if (line.Contains("Features :"))
+ {
+ currentHardware.info.Add("features", line.Split(':')[1].Trim().Split(',').ToList());
+ }
+ ////////////////////
+ ///////////////////
+ else if ((line.Contains("ID Cur Wor Thr RawValues(6) Attribute Name")))
+ {
+ currentHardware.smartAttributes = new List();
+ continue; // Skip header line
+ }
+ else if (line.Contains("ID RawValues(6) Attribute Name"))
+ {
+ currentHardware.smartAttributes = new List();
+ currentHardware.isNvme = true;
+ continue; // Skip header line
+ }
+ else if (line == "" || line.Contains("--") || line.Contains(" +0") || line.Contains(" 0") || line.Contains(": "))
+ {
+ continue;
+ }
+ else if (currentHardware.smartAttributes != null && currentHardware.isNvme == false)
+ {
+ string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+ var attributeName = string.Join(" ", parts, 5, parts.Length - 5);
+ if (attributeName.Contains("Temperature"))
+ {
+ continue;
+ }
+ long rawValue = 0;
+ try
+ {
+ rawValue = long.Parse(parts[4], System.Globalization.NumberStyles.HexNumber);
+ }
+ catch (Exception c)
+ {
+ Console.WriteLine(c.Message);
+ }
+ smartAttribute smartAttribute = new smartAttribute
+ {
+ id = parts[0],
+ currentValue = int.Parse(parts[1].Replace("_", "")),
+ worstValue = int.Parse(parts[2].Replace("_", "")),
+ threshold = int.Parse(parts[3].Replace("_", "")),
+ rawValue = rawValue,
+ attributeName = attributeName
+ };
+ currentHardware.smartAttributes.Add(smartAttribute);
+ }
+ else if (currentHardware.smartAttributes != null && currentHardware.isNvme == true)
+ {
+ string[] parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+ var attributeName = string.Join(" ", parts, 2, parts.Length - 2);
+ if (attributeName.Contains("Temperature"))
+ {
+ continue;
+ }
+ long rawValue = 0;
+ try
+ {
+ rawValue = long.Parse(parts[1], System.Globalization.NumberStyles.HexNumber);
+ }
+ catch (Exception c)
+ {
+ Console.WriteLine(c.Message);
+ }
+ smartAttribute smartAttribute = new smartAttribute
+ {
+ id = parts[0],
+ rawValue = rawValue,
+ attributeName = attributeName
+ };
+ currentHardware.smartAttributes.Add(smartAttribute);
+ }
+ }
+ }
+
+ // Add the last hardware entry if present
+ if (currentHardware != null)
+ {
+ hardwareList.Add(currentHardware);
+ }
+ hardwareList = hardwareList.Where(x => x.info.ContainsKey("model")).ToList();
+
+ // Now you have a list of hardware entries with all SMART attributes
+ return hardwareList;
+ }
+ static List ParseDriveLettersFromString(string input)
+ {
+ List driveLetters = new List();
+
+ // Use a regular expression to match drive letters
+ Regex regex = new Regex(@"[A-Za-z]:");
+ MatchCollection matches = regex.Matches(input);
+
+ foreach (Match match in matches)
+ {
+ // Extract the matched drive letter and add it to the list
+ driveLetters.Add(match.Value.Trim().Replace(":", ""));
+ }
+
+ return driveLetters;
+ }
+ }
+}
+
+
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/DiskInfoGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/DiskInfoGetter.cs
new file mode 100644
index 0000000..450e2ff
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/DiskInfoGetter.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Management;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Zal.Constants.Models;
+using ZalConsole.HelperFunctions;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class diskInfoGetter
+ {
+ static public diskInfo GetdiskInfo(int diskNumber,crystalDiskData? crystalDiskData)
+ {
+ foreach (ManagementObject disk in GlobalClass.Instance.getWin32DiskDrives())
+ {
+
+ //iterate until we get the disk number we want
+ int diskIndex = Convert.ToInt32(disk["Index"]);
+ if (diskIndex != diskNumber) continue;
+
+ diskInfo diskInfo = new diskInfo();
+ diskInfo.diskNumber = Convert.ToInt32(disk["Index"]);
+ diskInfo.totalSize = Convert.ToInt64(disk["Size"]);
+
+ foreach (ManagementObject partition in GlobalClass.Instance.getWin32DiskPartitions(diskNumber))
+ {
+
+ partitionInfo partitionInfo = new partitionInfo();
+ if (crystalDiskData != null)
+ {
+
+ partitionInfo.driveLetter = GetDriveLetter(partition);
+ var driveInfo = GetDriveByLetter(partitionInfo.driveLetter);
+ if (driveInfo != null)
+ {
+ partitionInfo.freeSpace = driveInfo.TotalFreeSpace;
+ partitionInfo.label = driveInfo.VolumeLabel;
+ }
+
+
+ }
+ else
+ {
+
+ }
+ partitionInfo.size = Convert.ToInt64(partition["Size"]);
+ diskInfo.partitions.Add(partitionInfo);
+ }
+
+ diskInfo.freeSpace = GetFreeSpaceForDisk(diskNumber);
+ return diskInfo;
+
+ }
+
+ return null;
+ }
+ //this is a fallback function in case crystalDiskData is not available
+ static private string GetDriveLetter(ManagementObject partition)
+ {
+ using (ManagementObjectSearcher searcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{partition["DeviceID"]}'}} WHERE AssocClass=Win32_LogicalDiskToPartition"))
+ {
+ foreach (ManagementObject logicalDisk in searcher.Get())
+ {
+
+ return logicalDisk["DeviceID"].ToString().Replace(":","");
+ }
+ }
+ return "";
+ }
+ private static DriveInfo? GetDriveByLetter(string driveName)
+ {
+ foreach (DriveInfo drive in DriveInfo.GetDrives())
+ {
+ string pattern = "[^a-zA-Z]";
+ string replacement = "";
+ Regex regex = new Regex(pattern);
+ string driveLetter = regex.Replace(drive.Name, replacement);
+ if (driveLetter == driveName)
+ {
+ return drive;
+
+ }
+ }
+ return null;
+ }
+ static private ulong GetFreeSpaceForDisk(int diskNumber)
+ {
+
+ var managementObjectDisks = GlobalClass.Instance.getWin32DiskPartitionsForFreeDiskSpace();
+ foreach (ManagementObject disk in managementObjectDisks)
+ {
+ var index = Convert.ToInt32(disk["Index"]);
+ if (index == diskNumber)
+ {
+ ManagementObjectSearcher partitionSearcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskDrive.DeviceID='{disk["DeviceID"]}'}} WHERE AssocClass=Win32_DiskDriveToDiskPartition");
+
+ ulong totalFreeSpace = 0;
+
+ foreach (ManagementObject partition in partitionSearcher.Get())
+ {
+ ManagementObjectSearcher logicalDiskSearcher = new ManagementObjectSearcher($"ASSOCIATORS OF {{Win32_DiskPartition.DeviceID='{partition["DeviceID"]}'}} WHERE AssocClass=Win32_LogicalDiskToPartition");
+
+ foreach (ManagementObject logicalDisk in logicalDiskSearcher.Get())
+ {
+ totalFreeSpace += Convert.ToUInt64(logicalDisk["FreeSpace"]);
+ }
+ }
+
+ return totalFreeSpace;
+ }
+ }
+
+ return 0;
+ }
+
+ }
+
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/FocusedWindowGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/FocusedWindowGetter.cs
new file mode 100644
index 0000000..e235bff
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/FocusedWindowGetter.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Management;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml.Linq;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ public class FocusedWindowGetter
+ {
+ [System.Runtime.InteropServices.DllImport("user32.dll")]
+ private static extern IntPtr GetForegroundWindow();
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+
+ public IList? getFocusedWindowProcessId()
+ {
+ IntPtr hwnd = GetForegroundWindow();
+
+ // The foreground window can be NULL in certain circumstances,
+ // such as when a window is losing activation.
+ if (hwnd == IntPtr.Zero)
+ return null;
+ uint pid;
+ GetWindowThreadProcessId(hwnd, out pid);
+ var proc = Process.GetProcessById(((int)pid));
+
+ return proc.GetChildProcesses().Select(process => process.Id).ToList();
+
+ }
+
+
+ }
+
+}
+public static class ProcessExtensions
+{
+ public static IList GetChildProcesses(this Process process)
+ {
+ var processes = new ManagementObjectSearcher(
+ $"Select * From Win32_Process Where ParentProcessID={process.Id}")
+ .Get()
+ .Cast()
+ .Select(mo =>
+ Process.GetProcessById(Convert.ToInt32(mo["ProcessID"])))
+ .ToList();
+ processes.Add(process);
+ Process[] processesByName = Process.GetProcessesByName(process.ProcessName);
+ foreach(var processByName in processesByName)
+ {
+ processes.Add(processByName);
+ }
+ return processes;
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/GpuUtilizationGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/GpuUtilizationGetter.cs
new file mode 100644
index 0000000..781d61c
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/GpuUtilizationGetter.cs
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Management.Automation;
+using ZalConsole.Constants.Models;
+using Zal;
+using Zal.HelperFunctions.SpecificFunctions;
+
+namespace ZalConsole.HelperFunctions.SpecificFunctions
+{
+ class GpuUtilizationGetter
+ {
+ //this function is based on this https://github.com/GameTechDev/PresentMon/issues/189
+ //and some modifications to make the data to be parsed easier from c# side.
+ public static Dictionary> getProcessesGpuUsage(bool skipBlackListedProcesses = true)
+ {
+ Dictionary> result = new Dictionary>();
+ var rawData = getRawDataFromPowershell();
+ var processInfos = GlobalClass.Instance.getProcessInfos();
+ foreach (var process in rawData)
+ {
+ Dictionary data = new Dictionary();
+ var splittedData = process.Split(',');
+ int pid = int.Parse(splittedData[0].Split('_')[1]);
+
+ double usage = 1;
+ try
+ {
+ usage = double.Parse(splittedData[1]);
+ }
+ catch { }
+ if (usage == 0) continue;
+
+ var p = Process.GetProcessById(pid);
+ try
+ {
+ var file = p.MainModule.FileName;
+ var icon = GlobalClass.Instance.getFileIcon(file);
+ data["icon"] = icon;
+ }
+ catch (Exception c)
+ {
+ Console.WriteLine(c.Message);
+ }
+
+ data["pid"] = pid;
+ data["name"] = p.ProcessName;
+ data["usage"] = usage;
+ ProcessInfo foundProcessInfo;
+ try
+ {
+ foundProcessInfo = processInfos.Where((a) => a.name == p.ProcessName).ToList().FirstOrDefault();
+ }
+ catch
+ {
+ foundProcessInfo = null;
+ }
+ if (foundProcessInfo != null)
+ {
+ if (skipBlackListedProcesses)
+ {
+ if (foundProcessInfo.isBlacklisted == true) continue;
+ }
+
+
+ if (foundProcessInfo.displayName != null) { data["name"] = foundProcessInfo.displayName; }
+ }
+
+ try
+ {
+ ProcesspathGetter.save(p.ProcessName, p.MainModule.FileName);
+ }
+ catch
+ {
+
+
+ }
+ result[p.ProcessName] = data;
+ }
+ return result;
+ }
+ private static List getRawDataFromPowershell()
+ {
+ List result = new List();
+ using (PowerShell PowerShellInstance = PowerShell.Create())
+ {
+ // Add the PowerShell script
+ string script = "$counter = Get-Counter '\\GPU Engine(*engtype_3D)\\Utilization Percentage';" +
+ "foreach ($sample in $counter.CounterSamples) {" +
+ "$sample.InstanceName + ',' + $sample.CookedValue" +
+ "}";
+ PowerShellInstance.AddScript(script);
+
+ // Invoke execution on the PowerShell object
+ Collection PSOutput = PowerShellInstance.Invoke();
+
+ // Check for errors
+ if (PowerShellInstance.Streams.Error.Count > 0)
+ {
+ Logger.Log($"error in powershell output: ```{PowerShellInstance.Streams.Error[0].Exception}```,```{PowerShellInstance.Streams.Error[0].ErrorDetails},{PowerShellInstance.Streams.Error[0].ScriptStackTrace}```, data: ```{Newtonsoft.Json.JsonConvert.SerializeObject(PSOutput.ToArray().Select(e => e.ToString()).ToList())}```");
+
+ }
+ else
+ {
+ // Output the results
+ foreach (PSObject outputItem in PSOutput)
+ {
+ result.Add(outputItem.ToString());
+ }
+ }
+ }
+ return result;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/IsAdminstratorChecker.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/IsAdminstratorChecker.cs
new file mode 100644
index 0000000..139e456
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/IsAdminstratorChecker.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Principal;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class IsAdminstratorChecker
+ {
+ public static bool IsAdministrator()
+ {
+ return (new WindowsPrincipal(WindowsIdentity.GetCurrent()))
+ .IsInRole(WindowsBuiltInRole.Administrator);
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/MonitorDataGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/MonitorDataGetter.cs
new file mode 100644
index 0000000..e009ac7
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/MonitorDataGetter.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Zal.Constants.Models;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class monitorDataGetter
+ {
+ public static List? getmonitorData()
+ {
+ var result = new List();
+ Screen[] screens = Screen.AllScreens;
+ foreach (Screen screen in screens)
+ {
+ var data = new monitorData();
+ data.name = screen.DeviceName;
+ data.height = (uint)screen.Bounds.Height;
+ data.width = (uint)screen.Bounds.Width;
+ data.isPrimary = screen.Primary;
+ data.bitsPerPixel = (uint)screen.BitsPerPixel;
+ result.Add(data);
+ }
+ return result;
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/NetworkSpeedGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/NetworkSpeedGetter.cs
new file mode 100644
index 0000000..c1d870b
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/NetworkSpeedGetter.cs
@@ -0,0 +1,145 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Threading;
+using System.Threading.Tasks;
+using Zal;
+using Zal.Constants.Models;
+
+namespace ZalConsole.HelperFunctions.SpecificFunctions
+{
+ class NetworkSpeedGetter
+ {
+ public networkSpeed primaryNetworkSpeed;
+ private Timer networkInterfaceTimer;
+ public List networkInterfaceDatas;
+ private List networkInterfaces;
+ public NetworkSpeedGetter()
+ {
+ networkSpeed s = new networkSpeed(0, 0);
+ primaryNetworkSpeed = s;
+
+ //run code that gets networkInterfaces every 5 seconds
+ networkInterfaceTimer = new Timer(async _ =>
+ {
+ // Call your method directly inside the timer
+ var result = await getNetworkInterfacesAsync();
+ networkInterfaceDatas = result;
+ }, null, 0, 5000);
+
+ //run code that periodically gets the primary network speed
+ Task.Run(async () =>
+ {
+
+ while (true)
+ {
+ string? primaryNetwork = (string?)LocalDatabase.Instance.readKey("primaryNetwork");
+ getPrimaryNetworkSpeedAsync(primaryNetwork);
+ }
+ });
+
+
+ }
+ private async Task getPrimaryNetworkSpeedAsync(string? primaryNetwork)
+ {
+
+ //var nics = networkInterfaces();
+ if (networkInterfaces == null)
+ {
+ networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces().ToList();
+ }
+
+ // Select desired NIC
+ var a = primaryNetwork;
+ var nic = networkInterfaces.SingleOrDefault(n => n.Name == primaryNetwork);
+ if (nic == null)
+ {
+ return;
+ }
+ var readsBr = new List();
+ var readsBs = new List();
+ var sw = new Stopwatch();
+ var lastBr = nic.GetIPv4Statistics().BytesReceived;
+ var lastBs = nic.GetIPv4Statistics().BytesSent;
+ for (var i = 0; i < 100; i++)
+ {
+
+ sw.Restart();
+ Thread.Sleep(100);
+ var elapsed = sw.Elapsed.TotalSeconds;
+ var br = nic.GetIPv4Statistics().BytesReceived;
+ var bs = nic.GetIPv4Statistics().BytesSent;
+
+ var localBr = (br - lastBr) / elapsed;
+ var localBs = (bs - lastBs) / elapsed;
+ lastBr = br;
+ lastBs = bs;
+
+ // Keep last 20, ~2 seconds
+ readsBr.Insert(0, localBr);
+ if (readsBr.Count > 20)
+ {
+ readsBr.RemoveAt(readsBr.Count - 1);
+ }
+ readsBs.Insert(0, localBs);
+ if (readsBs.Count > 20)
+ {
+ readsBs.RemoveAt(readsBs.Count - 1);
+ }
+ if (i % 10 == 0)
+ { // ~1 second
+ var brSec = readsBr.Sum() / readsBs.Count();
+ var bsSec = readsBs.Sum() / readsBs.Count();
+ networkSpeed s = new networkSpeed((int)brSec, (int)bsSec);
+ primaryNetworkSpeed = s;
+ }
+ }
+ }
+
+ private async Task> getNetworkInterfacesAsync()
+ {
+ var primaryNetwork = LocalDatabase.Instance.readKey("primaryNetwork");
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ return new List();
+
+ NetworkInterface[] interfaces
+ = NetworkInterface.GetAllNetworkInterfaces();
+ List data = new List();
+
+
+ foreach (NetworkInterface ni in interfaces)
+ {
+ var stats = ni.GetIPv4Statistics();
+ networkInterfaceData info = new networkInterfaceData();
+ info.name = ni.Name;
+ info.description = ni.Description;
+ info.status = ni.OperationalStatus.ToString();
+ info.id = ni.Id;
+ info.bytesReceived = stats.BytesReceived;
+ info.bytesSent = stats.BytesSent;
+ info.isPrimary = primaryNetwork == ni.Name;
+ data.Add(info);
+ }
+ data.Sort(delegate (networkInterfaceData c1, networkInterfaceData c2) { return c2.bytesReceived.CompareTo(c1.bytesReceived); });
+ if (primaryNetwork == null)
+ {
+ //if primary network interface isn't set, we'll set it to the network with highest downloaded bytes
+ await LocalDatabase.Instance.writeKey("primaryNetwork", data[0].name);
+ primaryNetwork = data[0].name;
+ }
+ //get the speed of primary network
+ return data;
+ }
+ }
+}
+public class networkInterfaceData
+{
+ public string name { get; set; }
+ public string description { get; set; }
+ public string status { get; set; }
+ public string id { get; set; }
+ public long bytesSent { get; set; }
+ public long bytesReceived { get; set; }
+ public bool isPrimary { get; set; }
+}
\ No newline at end of file
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/ProcessPathGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/ProcessPathGetter.cs
new file mode 100644
index 0000000..9f4d51a
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/ProcessPathGetter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class ProcesspathGetter
+ {
+ ///saves process path
+ public static void save(string name, string processPath)
+ {
+ var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Zal", "programs_path");
+ var folderPath = Directory.CreateDirectory(directory).FullName;
+ using (StreamWriter w = File.CreateText(Path.Combine(folderPath, name)))
+ {
+ w.Write(processPath);
+ }
+ }
+ public static string? load(string name)
+ {
+ try
+ {
+ var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Zal", "programs_path");
+ var folderPath = Directory.CreateDirectory(directory).FullName;
+ return File.ReadAllText(Path.Combine(folderPath, name));
+ }
+ catch { return null; }
+ }
+ }
+}
diff --git a/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/RamPieceDataGetter.cs b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/RamPieceDataGetter.cs
new file mode 100644
index 0000000..97096da
--- /dev/null
+++ b/zal_program/Zal/Backend/HelperFunctions/SpecificFunctions/RamPieceDataGetter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management;
+using System.Text;
+using System.Threading.Tasks;
+using Zal.Constants.Models;
+
+namespace Zal.HelperFunctions.SpecificFunctions
+{
+ class ramPieceDataGetter
+ {
+ public static List GetRamPiecesData()
+ {
+ var data = new List();
+ ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory");
+ foreach (ManagementObject obj in searcher.Get())
+ {
+ var ramData = new ramPieceData();
+ ramData.capacity = (ulong)obj["Capacity"];
+ ramData.manufacturer = (string)obj["Manufacturer"];
+ ramData.partNumber = (string)obj["PartNumber"];
+ ramData.speed = (uint)obj["Speed"];
+ data.Add(ramData);
+ }
+ return data;
+ }
+ }
+}
diff --git a/zal_program/Zal/CustomTheme.xaml b/zal_program/Zal/CustomTheme.xaml
new file mode 100644
index 0000000..a32d094
--- /dev/null
+++ b/zal_program/Zal/CustomTheme.xaml
@@ -0,0 +1,43 @@
+
+
+ #f44336
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zal_program/Zal/Functions/MajorFunctions/ApiManager.cs b/zal_program/Zal/Functions/MajorFunctions/ApiManager.cs
new file mode 100644
index 0000000..9d695aa
--- /dev/null
+++ b/zal_program/Zal/Functions/MajorFunctions/ApiManager.cs
@@ -0,0 +1,71 @@
+using Firebase.Auth.UI;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using Zal.Functions.Models;
+namespace Zal.Functions.MajorFunctions
+{
+ internal class ApiManager
+ {
+ public static async Task SendAlertToMobile(NotificationData notification, double value)
+ {
+ string displayName = $"{notification.childKey.displayName ?? notification.key.ToString()} {ConvertCamelToSpaced(notification.childKey.keyName)}";
+ string factorTypeText = notification.factorType == NotificationFactorType.Lower ? "fell below" : "reached";
+ string body = $"{displayName} {factorTypeText} {FormatDouble(value)}{notification.childKey.unit}";
+
+ await SendDataToDatabase("pc_message", new Dictionary
+ {
+ { "title", "ALERT!" },
+ { "body", body }
+ });
+ }
+ public static async Task SendDataToDatabase(string route, Dictionary data = null)
+ {
+ // Assuming FirebaseAuth is a class with a static property 'Instance' and 'Instance.TokenProvider' is a property returning a token.
+ string idToken = await FirebaseUI.Instance.Client.User.GetIdTokenAsync();
+
+ string databaseUrl = "https://zalapp.com/api"; // Replace this with your database URL
+ string url = $"{databaseUrl}/{route}";
+
+ string json = data != null ? JsonConvert.SerializeObject(data) : "{}";
+
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+
+ using (var client = new HttpClient())
+ {
+ client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", idToken);
+ return await client.PostAsync(url, content);
+ }
+ }
+ private static string FormatDouble(double number)
+ {
+ string formattedString = number.ToString((number == (int)number) ? "F0" : "F1");
+ return formattedString.EndsWith(".0") ? formattedString.Split('.')[0] : formattedString;
+ }
+ static string ConvertCamelToSpaced(string camelCase)
+ {
+ if (string.IsNullOrEmpty(camelCase))
+ return camelCase;
+
+ StringBuilder spacedString = new StringBuilder();
+ spacedString.Append(camelCase[0]);
+
+ for (int i = 1; i < camelCase.Length; i++)
+ {
+ if (char.IsUpper(camelCase[i]))
+ {
+ spacedString.Append(' ');
+ spacedString.Append(camelCase[i]);
+ }
+ else
+ {
+ spacedString.Append(camelCase[i]);
+ }
+ }
+
+ return spacedString.ToString();
+ }
+ }
+}
diff --git a/zal_program/Zal/Functions/MajorFunctions/DataManager.cs b/zal_program/Zal/Functions/MajorFunctions/DataManager.cs
new file mode 100644
index 0000000..2bd7531
--- /dev/null
+++ b/zal_program/Zal/Functions/MajorFunctions/DataManager.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Zal;
+using Zal.Constants.Models;
+using Zal.MajorFunctions;
+
+namespace Zal.Functions.MajorFunctions
+{
+ ///
+ /// this class is responsible for getting computerdata, collect charts and send them to mobile & the server.
+ ///
+ public class DataManager
+ {
+ //if this is true, the loop will run every 1 second. if false, the loop will run every 5 seconds.
+ private bool isMobileConnected = false;
+ private EventHandler computerDataReceived;
+ private ChartsDataManager chartsDataManager = new ChartsDataManager();
+ public DataManager(EventHandler computerDataReceived)
+ {
+ this.computerDataReceived = computerDataReceived;
+ startLoop();
+
+ }
+ public void setMobileConnectionState(bool state)
+ {
+ isMobileConnected = state;
+ sendDataToMobile();
+ }
+ private async Task startLoop()
+ {
+ await Task.Delay(2000);
+ while (true)
+ {
+ if (isMobileConnected)
+ {
+ sendDataToMobile();
+ }
+ else
+ {
+ getComputerDataAsync();
+ }
+ //wait before getting data again.
+ await Task.Delay(isMobileConnected ? 900 : 5000);
+ }
+ }
+ private async Task getComputerDataAsync()
+ {
+ try
+ {
+ var data = await FrontendGlobalClass.Instance.backend?.getComputerDataAsync();
+ if (data != null)
+ {
+ computerDataReceived.Invoke(null, data);
+ FrontendGlobalClass.Instance.notificationsManager.checkNotifications(data);
+ }
+
+ return data;
+
+ }
+
+ catch (Exception e)
+ {
+ Logger.LogError("error getting computerdata", e);
+ }
+ return null;
+ }
+ private async Task sendDataToMobile()
+ {
+
+ var data = new Dictionary();
+ var computerData = await getComputerDataAsync();
+ data["computerData"] = computerData;
+ if (computerData != null)
+ {
+ data["charts"] = await chartsDataManager.updateAsync(computerData);
+
+ //this whole thing is just to replace the gpus with only the primary gpu
+ var serializedComputerData = Newtonsoft.Json.JsonConvert.SerializeObject(computerData);
+ var dictionaryComputerData = Newtonsoft.Json.JsonConvert.DeserializeObject>(serializedComputerData);
+ dictionaryComputerData["gpuData"] = await ChartsDataManager.getPrimaryGpu(computerData);
+ dictionaryComputerData["availableGpus"] = computerData.gpuData.Select(gpu => gpu.name).ToList();
+ data["computerData"] = dictionaryComputerData;
+ }
+ var compressedData = CompressGzip(Newtonsoft.Json.JsonConvert.SerializeObject(data));
+ FrontendGlobalClass.Instance.webrtc?.sendMessage("pc_data", compressedData);
+ }
+ static string CompressGzip(string text)
+ {
+ byte[] enCodedJson = Encoding.UTF8.GetBytes(text);
+
+ using (MemoryStream memoryStream = new MemoryStream())
+ {
+ using (GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress))
+ {
+ gzipStream.Write(enCodedJson, 0, enCodedJson.Length);
+ }
+
+ byte[] gZipJson = memoryStream.ToArray();
+ string base64Json = Convert.ToBase64String(gZipJson);
+ return base64Json;
+ }
+ }
+
+ }
+}
+
+class ChartsDataManager
+{
+ private Dictionary> data = new Dictionary>();
+ public ChartsDataManager() { }
+
+ public async Task>> updateAsync(computerData computerData)
+ {
+ var primaryGpu = await getPrimaryGpu(computerData);
+ var empty = new List