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
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public class C64HostConfig : IHostSystemConfig, ICloneable
//public const string DefaultCorsProxyURL = "https://api.allorigins.win/raw?url="; // Doesn't work reliably
//public const string DefaultCorsProxyURL = "https://corsproxy.io/?url="; // Stopped being possible to download binary files on free tier
//public const string DefaultCorsProxyURL = "https://proxy.corsfix.com/?url="; // Only free from localhost
public const string DefaultCorsProxyURL = "https://cors-anywhere.com/";
//public const string DefaultCorsProxyURL = "https://cors-anywhere.com/"; // Only works from localhost
public const string DefaultCorsProxyURL = "https://api.codetabs.com/v1/proxy?quest=";

private C64SystemConfig _systemConfig = new();
ISystemConfig IHostSystemConfig.SystemConfig => _systemConfig;
Expand All @@ -31,7 +32,32 @@ public C64SystemConfig SystemConfig

public C64AvaloniaInputConfig InputConfig { get; set; } = new C64AvaloniaInputConfig();

public string CorsProxyURL { get; set; } = DefaultCorsProxyURL;
/// <summary>
/// Cors Proxy address override.
/// If set to null or empty, the default CORS proxy URL will be used when running in WebAssembly. When running on desktop, this setting is ignored and no CORS proxy will be used.
/// </summary>
/// <value></value>
public string? CorsProxyOverrideURL { get; set; } = null;

/// <summary>
/// Return the current CORS proxy URL to use.
/// If running in WebAssembly, this will return the CorsProxyOverrideURL if set, or the DefaultCorsProxyURL if CorsProxyOverrideURL is null or empty.
/// If not running in WebAssembly, this will return null to indicate that no CORS proxy should be used.
/// </summary>
/// <returns></returns> <summary>
///
/// </summary>
/// <returns></returns>
public string GetCorsProxyURL()
{
if (!PlatformDetection.IsRunningInWebAssembly())
{
// CORS proxy is only needed when running in WebAssembly, so return null to not use any proxy when running on desktop
return null!;
}
// If running in WebAssembly, return the configured CORS proxy URL, or the default if not set
return string.IsNullOrEmpty(CorsProxyOverrideURL) ? DefaultCorsProxyURL : CorsProxyOverrideURL;
}

private bool _basicAIAssistantDefaultEnabled;
[JsonIgnore]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class C64ConfigDialogViewModel : ViewModelBase
private RenderTargetOption? _selectedRenderTarget;
private bool _suppressRenderTargetUpdate;

private string _corsProxyOverrideURL = string.Empty;

// AI Coding Assistant properties - now using config objects
private CodeSuggestionBackendTypeEnum _selectedAIBackendType;
private ApiConfig _openAIConfig = new();
Expand All @@ -61,6 +63,7 @@ public class C64ConfigDialogViewModel : ViewModelBase
public ReactiveCommand<Unit, Unit> DownloadRomsToFilesCommand { get; }
public ReactiveCommand<Unit, Unit> ClearRomsCommand { get; }
public ReactiveCommand<Unit, Unit> TestAIBackendCommand { get; }
public ReactiveCommand<Unit, Unit> ResetCorsProxyOverrideURLCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<Unit, Unit> CancelCommand { get; }

Expand All @@ -86,6 +89,7 @@ public C64ConfigDialogViewModel(
AudioEnabled = _workingConfig.SystemConfig.AudioEnabled;

RomDirectory = _workingConfig.SystemConfig.ROMDirectory;
CorsProxyOverrideURL = _workingConfig.CorsProxyOverrideURL ?? string.Empty;

// Initialize AI Coding Assistant properties
SelectedAIBackendType = _workingConfig.CodeSuggestionBackendType;
Expand Down Expand Up @@ -117,6 +121,14 @@ public C64ConfigDialogViewModel(
TestAIBackendAsync,
outputScheduler: RxApp.MainThreadScheduler);

ResetCorsProxyOverrideURLCommand = ReactiveCommandHelper.CreateSafeCommand(
() =>
{
CorsProxyOverrideURL = string.Empty;
return Task.CompletedTask;
},
outputScheduler: RxApp.MainThreadScheduler);

SaveCommand = ReactiveCommandHelper.CreateSafeCommand(
async () =>
{
Expand Down Expand Up @@ -269,6 +281,21 @@ public string RomDirectory
}
}

public string CorsProxyOverrideURL
{
get => _corsProxyOverrideURL;
set
{
if (_corsProxyOverrideURL == value)
return;

this.RaiseAndSetIfChanged(ref _corsProxyOverrideURL, value);
_workingConfig.CorsProxyOverrideURL = string.IsNullOrEmpty(value) ? null : value;
}
}

public static string CorsProxyOverrideURLWatermark => C64HostConfig.DefaultCorsProxyURL;

public RenderProviderOption? SelectedRenderProvider
{
get => _selectedRenderProvider;
Expand Down Expand Up @@ -331,8 +358,9 @@ public async Task AutoDownloadRomsToByteArrayAsync()

foreach (var romDownload in _workingConfig.SystemConfig.ROMDownloadUrls)
{
var fullROMUrl = !string.IsNullOrEmpty(_workingConfig.CorsProxyURL)
? $"{_workingConfig.CorsProxyURL}{Uri.EscapeDataString(romDownload.Value)}"
var proxyUrl = _workingConfig.GetCorsProxyURL();
var fullROMUrl = !string.IsNullOrEmpty(proxyUrl)
? $"{proxyUrl}{Uri.EscapeDataString(romDownload.Value)}"
: romDownload.Value;

var romBytes = await _httpClient.GetByteArrayAsync(fullROMUrl);
Expand Down Expand Up @@ -1034,6 +1062,7 @@ private void UpdateValidationMessageFromConfig()
private void ApplyWorkingConfigToOriginal()
{
_originalConfig.SystemConfig.ROMDirectory = _workingConfig.SystemConfig.ROMDirectory;
_originalConfig.CorsProxyOverrideURL = _workingConfig.CorsProxyOverrideURL;
_originalConfig.SystemConfig.AudioEnabled = _workingConfig.SystemConfig.AudioEnabled;
_originalConfig.SystemConfig.KeyboardJoystickEnabled = _workingConfig.SystemConfig.KeyboardJoystickEnabled;
_originalConfig.SystemConfig.KeyboardJoystick = _workingConfig.SystemConfig.KeyboardJoystick;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ private async Task LoadPreloadedDiskImage()
_loggerFactory,
_httpClient,
HostApp!,
corsProxyUrl: PlatformDetection.IsRunningInWebAssembly() ? c64HostConfig.CorsProxyURL : null);
corsProxyUrl: c64HostConfig.GetCorsProxyURL());
}

await _d64AutoDownloadAndRun.DownloadAndRunDiskImage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,35 @@
</Border>
</StackPanel>

<!-- Network Section (browser only) -->
<StackPanel Width="460" Classes="wrap-item"
IsVisible="{Binding IsRunningInWebAssembly}">
<Border Classes="content-section">
<StackPanel Classes="spacing-tight">
<TextBlock Text="Network"/>

<Grid ColumnDefinitions="90,*,Auto" Classes="spacing-tight">
<TextBlock Grid.Column="0"
Text="CORS proxy:"
Classes="secondary-text"/>
<TextBox Grid.Column="1"
Text="{Binding CorsProxyOverrideURL, Mode=TwoWay}"
Watermark="{Binding CorsProxyOverrideURLWatermark}"
Classes="field-aligned"
KeyDown="CorsProxyTextBox_KeyDown"/>
<Button Grid.Column="2"
Content="Reset"
Command="{Binding ResetCorsProxyOverrideURLCommand}"
Margin="4,0,0,0"
Height="32"
Padding="12,0"
VerticalContentAlignment="Center"
Classes=""/>
</Grid>
</StackPanel>
</Border>
</StackPanel>

<!-- AI Coding Assistant Section -->
<StackPanel Width="460" Classes="wrap-item">
<Border Classes="content-section">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,35 @@ private void CloseOverlay()
}
}

// In Avalonia WASM on macOS, TextBox default key bindings only include Ctrl+C/V, not Meta (CMD).
// This handler explicitly handles CMD+C/V/X/A so copy/paste works in the browser.
private void CorsProxyTextBox_KeyDown(object? sender, KeyEventArgs e)
{
if (sender is not TextBox textBox) return;
if ((e.KeyModifiers & (KeyModifiers.Meta | KeyModifiers.Control)) == 0) return;

if (e.Key == Key.C)
{
textBox.Copy();
e.Handled = true;
}
else if (e.Key == Key.V)
{
textBox.Paste();
e.Handled = true;
}
else if (e.Key == Key.X)
{
textBox.Cut();
e.Handled = true;
}
else if (e.Key == Key.A)
{
textBox.SelectAll();
e.Handled = true;
}
}

private async void LoadRoms_Click(object? sender, RoutedEventArgs e)
{
if (TopLevel.GetTopLevel(this)?.StorageProvider == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class C64HostConfig : IHostSystemConfig, ICloneable
//public const string DefaultCorsProxyURL = "https://thingproxy.freeboard.io/fetch/"; // Doesn't seem to work with redirects
//public const string DefaultCorsProxyURL = "https://corsproxy.io/?url="; // Stopped being possible to download binary files on free tier
//public const string DefaultCorsProxyURL = "https://proxy.corsfix.com/?url="; // Only free from localhost
public const string DefaultCorsProxyURL = "https://cors-anywhere.com/";
//public const string DefaultCorsProxyURL = "https://cors-anywhere.com/"; // Only works from localhost
public const string DefaultCorsProxyURL = "https://api.codetabs.com/v1/proxy?quest=";

private C64SystemConfig _systemConfig;
ISystemConfig IHostSystemConfig.SystemConfig => _systemConfig;
Expand Down
Loading