Skip to content

Commit

Permalink
#6: Automatically fix qBittorrent listening socket errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Aldaviva committed Aug 3, 2024
1 parent d0ddbf5 commit 594ad9b
Show file tree
Hide file tree
Showing 19 changed files with 262 additions and 143 deletions.
10 changes: 10 additions & 0 deletions PortForwardingManager.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PublicFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=15b5b1f1_002D457c_002D4ca6_002Db278_002D5615aedc07d3/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=236f7aa5_002D7b06_002D43ca_002Dbf2a_002D9b31bfcff09a/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=53eecf85_002Dd821_002D40e8_002Dac97_002Dfdb734542b84/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=61a991a4_002Dd0a3_002D4d19_002D90a5_002Df8f4d75c30c1/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local variables"&gt;&lt;ElementKinds&gt;&lt;Kind Name="LOCAL_VARIABLE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=669e5282_002Dfb4b_002D4e90_002D91e7_002D07d269d04b60/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="CONSTANT_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=70345118_002D4b40_002D4ece_002D937c_002Dbbeb7a0b2e70/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a0b4bc4d_002Dd13b_002D4a37_002Db37e_002Dc9c6864e4302/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="NAMESPACE" /&gt;&lt;Kind Name="CLASS" /&gt;&lt;Kind Name="STRUCT" /&gt;&lt;Kind Name="ENUM" /&gt;&lt;Kind Name="DELEGATE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=a7a3339e_002D4e89_002D4319_002D9735_002Da9dc4cb74cc7/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Any" AccessRightKinds="Any" Description="Interfaces"&gt;&lt;ElementKinds&gt;&lt;Kind Name="INTERFACE" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AaBb" /&gt;&lt;ExtraRule Prefix="μ" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
Expand Down Expand Up @@ -52,5 +61,6 @@
<s:Boolean x:Key="/Default/Environment/Filtering/ExcludeCoverageFilters/=Smocks_003B_002A_003B_002A_003B_002A/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/Filtering/ExcludeCoverageFilters/=Test_003B_002A_003B_002A_003B_002A/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EdotCover_002EIde_002ECore_002EFilterManagement_002EModel_002ESolutionFilterSettingsManagerMigrateSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/FilterSettingsManager/AttributeFilterXml/@EntryValue">&lt;data /&gt;</s:String>
<s:String x:Key="/Default/FilterSettingsManager/CoverageFilterXml/@EntryValue">&lt;data&gt;&lt;IncludeFilters /&gt;&lt;ExcludeFilters&gt;&lt;Filter ModuleMask="NotificationArea" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Test" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;Filter ModuleMask="Smocks" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /&gt;&lt;/ExcludeFilters&gt;&lt;/data&gt;</s:String></wpf:ResourceDictionary>

This file was deleted.

22 changes: 12 additions & 10 deletions PortForwardingService/PortForwardingService.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BC93B5EA-E5FF-465D-9829-D24C7B05EF1B}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<RootNamespace>PortForwardingService</RootNamespace>
<AssemblyName>PortForwardingService</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<LangVersion>latest</LangVersion>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
Expand All @@ -23,8 +25,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
Expand All @@ -34,7 +34,6 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
Expand All @@ -49,11 +48,14 @@
<Reference Include="System.ServiceProcess" />
</ItemGroup>
<ItemGroup>
<Compile Include="ListeningPortEditors\ConfigurationFileListeningPortEditor.cs" />
<Compile Include="ListeningPortEditors\ListeningPortEditor.cs" />
<Compile Include="PiaForwardedPortMonitor.cs" />
<Compile Include="PrivateInternetAccessException.cs" />
<Compile Include="QbittorrentManager.cs" />
<Compile Include="qBittorrent\ListeningPortEditors\ConfigurationFileListeningPortEditor.cs" />
<Compile Include="qBittorrent\ListeningPortEditors\ListeningPortEditor.cs" />
<Compile Include="qBittorrent\Data\Preferences.cs" />
<Compile Include="qBittorrent\QbittorrentClient.cs" />
<Compile Include="PrivateInternetAccess\PiaForwardedPortMonitor.cs" />
<Compile Include="PrivateInternetAccess\PrivateInternetAccessException.cs" />
<Compile Include="qBittorrent\QbittorrentManager.cs" />
<Compile Include="qBittorrent\Data\TransferInfo.cs" />
<Compile Include="Service.cs">
<SubType>Component</SubType>
</Compile>
Expand All @@ -62,7 +64,7 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ListeningPortEditors\WebApiListeningPortEditor.cs" />
<Compile Include="qBittorrent\ListeningPortEditors\WebApiListeningPortEditor.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#nullable enable

using KoKo.Property;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using KoKo.Property;

namespace PortForwardingService;
namespace PortForwardingService.PrivateInternetAccess;

public class PiaForwardedPortMonitor: IDisposable {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#nullable enable
using System;

using System;

namespace PortForwardingService;
namespace PortForwardingService.PrivateInternetAccess;

public class PrivateInternetAccessException: Exception {

Expand Down
4 changes: 2 additions & 2 deletions PortForwardingService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ private static void Main(string[] args) {
Service service = new();

if (Environment.UserInteractive) {
ManualResetEvent unblockMainThread = new(false);
ManualResetEventSlim unblockMainThread = new(false);

Console.CancelKeyPress += delegate(object _, ConsoleCancelEventArgs eventArgs) {
eventArgs.Cancel = true;
Expand All @@ -22,7 +22,7 @@ private static void Main(string[] args) {

service.onStart(args);

unblockMainThread.WaitOne(); //block while service runs, then exit once user hits Ctrl+C
unblockMainThread.Wait(); //block while service runs, then exit once user hits Ctrl+C
} else {
ServiceBase.Run(service);
}
Expand Down
8 changes: 4 additions & 4 deletions PortForwardingService/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Reflection;
using System.Reflection;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
Expand All @@ -9,7 +9,7 @@
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Ben Hutchison")]
[assembly: AssemblyProduct("PortForwardingService")]
[assembly: AssemblyCopyright(2023 Ben Hutchison")]
[assembly: AssemblyCopyright(2024 Ben Hutchison")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -31,5 +31,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyVersion("1.1.0.0")]
[assembly: AssemblyFileVersion("1.1.0.0")]
37 changes: 0 additions & 37 deletions PortForwardingService/QbittorrentManager.cs

This file was deleted.

14 changes: 10 additions & 4 deletions PortForwardingService/Service.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#nullable enable

using PortForwardingService.PrivateInternetAccess;
using PortForwardingService.qBittorrent;
using System;
using System.ServiceProcess;

Expand All @@ -8,25 +10,29 @@ namespace PortForwardingService;
public partial class Service: ServiceBase {

private readonly PiaForwardedPortMonitor piaForwardedPortMonitor = new();
private readonly QbittorrentManager qBittorrentManager = new();
private readonly QbittorrentManager qBittorrentManager;

public Service() {
qBittorrentManager = new QbittorrentManager(piaForwardedPortMonitor);
InitializeComponent();
}

protected override void OnStart(string[] args) {
piaForwardedPortMonitor.forwardedPort.PropertyChanged += (_, eventArgs) => {
piaForwardedPortMonitor.forwardedPort.PropertyChanged += async (_, eventArgs) => {
Console.WriteLine($"PIA forwarded port changed to {eventArgs.NewValue?.ToString() ?? "null"}");

ushort? qBittorrentListeningPort = qBittorrentManager.getQbittorrentConfigurationListeningPort();
ushort? qBittorrentListeningPort = await qBittorrentManager.getQbittorrentConfigurationListeningPort();

if (eventArgs.NewValue is { } piaForwardedPort && piaForwardedPort != qBittorrentListeningPort) {
qBittorrentManager.setQbittorrentListeningPort(piaForwardedPort);
await qBittorrentManager.setQbittorrentListeningPort(piaForwardedPort);
}
};

piaForwardedPortMonitor.listenForPiaPortForwardChanges();
Console.WriteLine("Listening for forwarded port changes from PIA...");

qBittorrentManager.listenForSocketErrors();
Console.WriteLine("Listening for socket errors from qBittorrent...");
}

protected override void OnStop() {
Expand Down
37 changes: 0 additions & 37 deletions PortForwardingService/Service1.Designer.cs

This file was deleted.

2 changes: 1 addition & 1 deletion PortForwardingService/app.manifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<assemblyIdentity version="1.0.0.0" name="PortForwardingService"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
Expand Down
1 change: 1 addition & 0 deletions PortForwardingService/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
}
},
".NETFramework,Version=v4.8/win": {},
".NETFramework,Version=v4.8/win-arm64": {},
".NETFramework,Version=v4.8/win-x64": {},
".NETFramework,Version=v4.8/win-x86": {}
}
Expand Down
14 changes: 14 additions & 0 deletions PortForwardingService/qBittorrent/Data/Preferences.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#nullable enable

using Newtonsoft.Json;

namespace PortForwardingService.qBittorrent.Data;

// Other preferences are excluded
// See full list at https://github.com/qbittorrent/qBittorrent/wiki/WebUI-API-(qBittorrent-4.1)#get-application-preferences
internal class Preferences {

[JsonProperty("listen_port")]
public ushort listeningPort { get; set; }

}
Loading

0 comments on commit 594ad9b

Please sign in to comment.