Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ dotnet_naming_rule.interface_names_must_begin_with_I.symbols = interfaces
dotnet_naming_rule.interface_names_must_begin_with_I.style = pascal_begin_with_I_style
dotnet_naming_rule.interface_names_must_begin_with_I.severity = warning

dotnet_naming_rule.private_const_fields_none.symbols = private_const_fields
dotnet_naming_rule.private_const_fields_none.style = camel_begin_with_underscore_style
dotnet_naming_rule.private_const_fields_none.severity = none

dotnet_naming_rule.private_and_protected_fields_must_begin_with_underscore.symbols = private_fields
dotnet_naming_rule.private_and_protected_fields_must_begin_with_underscore.style = camel_begin_with_underscore_style
dotnet_naming_rule.private_and_protected_fields_must_begin_with_underscore.severity = warning
Expand All @@ -79,6 +83,10 @@ dotnet_naming_symbols.interfaces.applicable_accessibilities = *
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private,protected,protected_internal

dotnet_naming_symbols.private_const_fields.applicable_kinds = field
dotnet_naming_symbols.private_const_fields.applicable_accessibilities = private, protected, protected_internal
dotnet_naming_symbols.private_const_fields.required_modifiers = const

dotnet_naming_symbols.public_and_internal_members.applicable_kinds = class,struct,enum,property,method,event,delegate,field
dotnet_naming_symbols.public_and_internal_members.applicable_accessibilities = public,internal

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ concurrency:
jobs:
Build:
name: Build on self-hosted
runs-on: m2mini-win11
runs-on: M4700
permissions:
contents: write
defaults:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace BrowseRouter.Config;
namespace BrowseRouter.Config.Loaders;

internal interface IConfigLoader
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace BrowseRouter.Config;
namespace BrowseRouter.Config.Loaders;

internal class IniConfigLoader(string path) : IConfigLoader
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json;

namespace BrowseRouter.Config;
namespace BrowseRouter.Config.Loaders;

internal class JsonConfigLoader(string path) : IConfigLoader
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using BrowseRouter.Infrastructure;
using BrowseRouter.Config;
using BrowseRouter.Config.Loaders;
using BrowseRouter.Services;

namespace BrowseRouter.Config;
namespace BrowseRouter.Infrastructure;

public static class ConfigServiceFactory
{
Expand Down
3 changes: 0 additions & 3 deletions BrowseRouter/Interop/Win32/Kernel32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,5 @@ public static class Kernel32
[DllImport("kernel32.dll")]
private static extern bool AttachConsole(uint dwProcessId);

/// <summary>
/// This enables e.g. showing --help in Terminal / cmd text even though this is a WinExe app.
/// </summary>
public static void AttachToParentConsole() => AttachConsole(ATTACH_PARENT_PROCESS);
}
40 changes: 19 additions & 21 deletions BrowseRouter/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Runtime.InteropServices;
using BrowseRouter.Config;
using BrowseRouter.Config;
using BrowseRouter.Infrastructure;
using BrowseRouter.Interop.Win32;
using BrowseRouter.Services;
Expand All @@ -8,14 +7,14 @@ namespace BrowseRouter;

public static class Program
{

private static async Task Main(string[] args)
{
// This enables e.g. showing --help in Terminal / cmd text even though this is a WinExe app.
Kernel32.AttachToParentConsole();

if (args.Length == 0)
{
await new DefaultBrowserService(new NotifyService(false)).RegisterOrUnregisterAsync();
await new DefaultBrowserService(new NotifyService()).RegisterOrUnregisterAsync();
return;
}

Expand All @@ -28,24 +27,25 @@ private static async Task Main(string[] args)

private static async Task RunAsync(string arg)
{
Func<bool> getIsOption = () => arg.StartsWith('-') || arg.StartsWith('/');

bool isOption = getIsOption();
while (getIsOption())
bool isOption = GetIsOption(arg);
while (GetIsOption(arg))
{
arg = arg[1..];
}

if (isOption)
{
await RunOption(arg);
await RunOptionAsync(arg);
return;
}

await LaunchUrlAsyc(arg);

}

private static async Task<bool> RunOption(string arg)
private static bool GetIsOption(string arg) => arg.StartsWith('-') || arg.StartsWith('/');

private static async Task<bool> RunOptionAsync(string arg)
{
if (string.Equals(arg, "h") || string.Equals(arg, "help"))
{
Expand All @@ -55,13 +55,13 @@ private static async Task<bool> RunOption(string arg)

if (string.Equals(arg, "r") || string.Equals(arg, "register"))
{
await new DefaultBrowserService(new NotifyService(false)).RegisterAsync();
await new DefaultBrowserService(new NotifyService()).RegisterAsync();
return true;
}

if (string.Equals(arg, "u") || string.Equals(arg, "unregister"))
{
await new DefaultBrowserService(new NotifyService(false)).UnregisterAsync();
await new DefaultBrowserService(new NotifyService()).UnregisterAsync();
return true;
}

Expand All @@ -70,22 +70,20 @@ private static async Task<bool> RunOption(string arg)

private static async Task LaunchUrlAsyc(string url)
{
// Get the window title for whichever application is opening the URL.
ProcessService processService = new();
if (!processService.TryGetParentProcessTitle(out string windowTitle))
windowTitle = User32.GetActiveWindowTitle(); //if it didn't work we get the current foreground window name instead

IConfigService configService = await ConfigServiceFactory.CreateAsync();
Log.Preference = configService.GetLogPreference();
IConfigService config = await ConfigServiceFactory.CreateAsync();
Log.Preference = config.GetLogPreference();

NotifyPreference notifyPref = configService.GetNotifyPreference();
NotifyPreference notifyPref = config.GetNotifyPreference();
INotifyService notifier = notifyPref.IsEnabled switch
{
true => new NotifyService(notifyPref.IsSilent),
false => new EmptyNotifyService()
};

await new BrowserService(configService, notifier).LaunchAsync(url, windowTitle);
IBrowserService browsers = new BrowserService(config, notifier, new ProcessService());
ILaunchService launchService = new LaunchService(browsers, new ProcessService(), new WindowTitleService());

await launchService.LaunchUrlAsyc(url);
}

private static void ShowHelp()
Expand Down
18 changes: 11 additions & 7 deletions BrowseRouter/Services/BrowserService.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
using System.Diagnostics;
using BrowseRouter.Config;
using BrowseRouter.Config;
using BrowseRouter.Infrastructure;
using BrowseRouter.Model;

namespace BrowseRouter.Services;

public class BrowserService(IConfigService config, INotifyService notifier)
public interface IBrowserService
{
Task LaunchAsync(string rawUrl, string windowTitle);
}

public class BrowserService(IConfigService config, INotifyService notifier, IProcessService process) : IBrowserService
{
public async Task LaunchAsync(string rawUrl, string windowTitle)
{
Expand All @@ -16,7 +20,7 @@ public async Task LaunchAsync(string rawUrl, string windowTitle)
List<FilterPreference> filters = await config.GetFiltersAsync();

bool didFilter = FilterPreference.TryApply(filters, rawUrl, out string url);

if (didFilter)
Log.Write($"Filtered URL: {rawUrl} -> {url}");

Expand Down Expand Up @@ -50,16 +54,16 @@ public async Task LaunchAsync(string rawUrl, string windowTitle)
Log.Write($"Launching {path} with args \"{args}\"");

string name = GetAppName(path);

path = Environment.ExpandEnvironmentVariables(path);

if (!Actions.TryRun(() => Process.Start(path, args)))
if (!Actions.TryRun(() => process.Start(path, args)))
{
await notifier.NotifyAsync($"Error", $"Could not open {name}. Please check the log for more details.");
return;
}

await notifier.NotifyAsync($"Opening {name}", $"{(didFilter ? "Filtered ":"")}URL: {url}");
await notifier.NotifyAsync($"Opening {name}", $"{(didFilter ? "Filtered " : "")}URL: {url}");
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using System.Text.Json;
using BrowseRouter.Config;
using BrowseRouter.Infrastructure;
using BrowseRouter.Model;

namespace BrowseRouter.Config;
namespace BrowseRouter.Services;

internal class ConfigService(Config config) : IConfigService
internal class ConfigService(Config.Config config) : IConfigService
{
public NotifyPreference GetNotifyPreference() => new()
{
Expand Down
23 changes: 23 additions & 0 deletions BrowseRouter/Services/LaunchService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace BrowseRouter.Services;

public interface ILaunchService
{
Task LaunchUrlAsyc(string url);
}

public class LaunchService(
IBrowserService browsers,
IProcessService processes,
IWindowTitleService titles
) : ILaunchService
{
public async Task LaunchUrlAsyc(string url)
{
// Get the window title for whichever application is opening the URL.
if (!processes.TryGetParentProcessTitle(out string windowTitle))
// If it didn't work, fallback to the current foreground window name
windowTitle = titles.GetWindowTitle();

await browsers.LaunchAsync(url, windowTitle);
}
}
13 changes: 7 additions & 6 deletions BrowseRouter/Services/NotifyService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ public class NotifyService : INotifyService

private static nint _hIcon;
private static nint _hInstance = Kernel32.GetModuleHandle(App.ExePath);
private readonly bool _isSilent;
private readonly bool _noSound;

public NotifyService(bool isSilent)
public NotifyService(bool noSound = false)
{
_isSilent = isSilent;
_noSound = noSound;
LoadIcon();
}

private static bool LoadIcon(int size = 512) =>
Comctl32.LoadIconWithScaleDown(_hInstance, Icon.Application, size, size, out _hIcon) != 0;

Expand All @@ -38,7 +39,7 @@ public async Task NotifyAsync(string title, string message)
// Create a dummy window handle
nint hWnd = CreateDummyWindow();

NotifyIconData nid = GetNid(hWnd, title, message, _isSilent);
NotifyIconData nid = GetNid(hWnd, title, message, _noSound);

// Add the icon. This also adds it to the system tray.
Shell32.Shell_NotifyIcon(Shell32.NIM_ADD, ref nid);
Expand Down Expand Up @@ -76,7 +77,7 @@ public void Remove(NotifyIconData nid)
Shell32.Shell_NotifyIcon(Shell32.NIM_DELETE, ref nid);
}

private static NotifyIconData GetNid(nint hWnd, string title, string message, bool isSilent) => new NotifyIconData
private static NotifyIconData GetNid(nint hWnd, string title, string message, bool noSound) => new NotifyIconData
{
cbSize = Marshal.SizeOf(typeof(NotifyIconData)),
hWnd = hWnd,
Expand All @@ -88,7 +89,7 @@ public void Remove(NotifyIconData nid)
szTip = "BrowseRouter",
szInfo = message,
szInfoTitle = title,
dwInfoFlags = Shell32.NIIF_USER | Shell32.NIIF_LARGE_ICON | (isSilent ? Shell32.NIIF_NOSOUND : 0x00000000),
dwInfoFlags = Shell32.NIIF_USER | Shell32.NIIF_LARGE_ICON | (noSound ? Shell32.NIIF_NOSOUND : 0x00000000),
dwState = 0, // For the popup to be shown, the system tray icon must not be hidden, but we can hide it immediately after
dwStateMask = Shell32.NIS_HIDDEN,
uVersion = Shell32.NOTIFYICON_VERSION_4
Expand Down
Loading