-
Notifications
You must be signed in to change notification settings - Fork 3
Fixed appsettings.json cann't be copied successfully #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThe changes in this pull request involve significant modifications to the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant YounBot
participant Config
participant QrCodeLogin
User->>YounBot: Start Application
YounBot->>Config: Check appsettings.json
alt File Found
Config-->>YounBot: Load Configuration
YounBot->>QrCodeLogin: Initiate Login
QrCodeLogin-->>YounBot: Login Successful
else File Not Found
YounBot-->>User: No config file found
YounBot->>Config: Load default settings
end
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Outside diff range and nitpick comments (4)
YounBot.csproj (2)
21-24: Consider the implications of embedding appsettings.jsonWhile embedding the configuration file ensures it's always available and fixes the copying issue, this approach has important trade-offs:
- The configuration cannot be modified after deployment without recompiling
- This may complicate deployment scenarios where configuration needs to be environment-specific
- Changes to settings will require a new build and deployment
Consider whether a hybrid approach might be better:
- Keep the embedded file as a fallback
- Allow external configuration file to override embedded settings
Would you like me to provide an example of implementing the hybrid approach in Program.cs?
Switch to stable version 8.0.0 of Microsoft.Extensions packages
The stable version 8.0.0 of Microsoft.Extensions packages is now available, which should be used instead of the pre-release RC2 versions. Update all Microsoft.Extensions package references to version 8.0.0:
- Microsoft.Extensions.Configuration
- Microsoft.Extensions.Configuration.EnvironmentVariables
- Microsoft.Extensions.Configuration.Json
- Microsoft.Extensions.DependencyInjection
- Microsoft.Extensions.Hosting
- Microsoft.Extensions.Logging
🔗 Analysis chain
Line range hint
12-19: Review usage of pre-release packagesThe project is using RC2 versions of Microsoft.Extensions.* packages. While these align with .NET 8.0, consider:
- These are pre-release versions and may have breaking changes
- It's recommended to use stable versions for production deployments
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for stable versions of these packages curl -s https://api.nuget.org/v3-flatcontainer/microsoft.extensions.configuration/index.json | jq '.versions[] | select(contains("-") | not)' | tail -n 5Length of output: 195
Program.cs (2)
Line range hint
26-31: Remove redundant stream closing callsThe
usingstatements already ensure proper disposal of the streams. The explicitClose()calls are redundant and could potentially cause issues if the streams are already disposed.using var istr = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json")!; using var temp = File.Create("appsettings.json"); istr.CopyTo(temp); - istr.Close(); - temp.Close();
Line range hint
20-34: Improve file handling and error managementThe current implementation lacks proper error handling for file operations and uses hardcoded paths. Consider the following improvements:
- Add try-catch blocks for file operations
- Use Path.Combine for file paths
- Add proper error messages for common scenarios (permissions, disk space, etc.)
- if (!File.Exists("appsettings.json")) + var configPath = Path.Combine(AppContext.BaseDirectory, "appsettings.json"); + if (!File.Exists(configPath)) { + try + { var assm = Assembly.GetExecutingAssembly(); var resourceStream = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json"); if (resourceStream == null) { throw new FileNotFoundException("Required embedded resource 'appsettings.json' was not found. Ensure it's properly embedded in the assembly."); } - using var istr = resourceStream; - using var temp = File.Create("appsettings.json"); - istr.CopyTo(temp); - istr.Close(); - temp.Close(); + using (var istr = resourceStream) + using (var temp = File.Create(configPath)) + { + istr.CopyTo(temp); + } + } + catch (UnauthorizedAccessException) + { + Console.WriteLine("Error: Unable to create appsettings.json. Please check file permissions."); + return; + } + catch (IOException ex) + { + Console.WriteLine($"Error creating configuration file: {ex.Message}"); + return; + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (2)
Program.cs(1 hunks)YounBot.csproj(1 hunks)
🔇 Additional comments (1)
Program.cs (1)
26-26: Verify the embedded resource exists in the assembly
Let's ensure that the resource is properly embedded in the assembly.
✅ Verification successful
Let me gather more information to verify the embedded resource configuration.
The embedded resource is properly configured ✅
The verification shows that:
appsettings.jsonexists atResources/appsettings.json- The file is correctly configured as an embedded resource in the project file with:
<None Remove="Resources\appsettings.json" /> <EmbeddedResource Include="Resources\appsettings.json" />
- The resource path used in the code matches the configured path
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if appsettings.json is properly embedded as a resource
# Search for resource inclusion in project file
rg -l "appsettings\.json.*EmbeddedResource"
# Search for resource path in all files
rg "YounBot\.Resources\.appsettings\.json"
Length of output: 201
Script:
#!/bin/bash
# Check project files for resource configuration
fd -e csproj -x cat {}
# Check if appsettings.json exists and its location
fd appsettings.json
# Check for any Resources directory
fd -t d Resources
Length of output: 1303
|
|
||
| var assm = Assembly.GetExecutingAssembly(); | ||
| using var istr = assm.GetManifestResourceStream("Lagrange.OneBot.Resources.appsettings.json")!; | ||
| using var istr = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json")!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add proper error handling for resource stream access
The null-forgiving operator (!) assumes the embedded resource will always exist, which could lead to a NullReferenceException if the resource is missing. Consider adding proper error handling.
- using var istr = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json")!;
+ var resourceStream = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json");
+ if (resourceStream == null)
+ {
+ throw new FileNotFoundException("Required embedded resource 'appsettings.json' was not found. Ensure it's properly embedded in the assembly.");
+ }
+ using var istr = resourceStream;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| using var istr = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json")!; | |
| var resourceStream = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json"); | |
| if (resourceStream == null) | |
| { | |
| throw new FileNotFoundException("Required embedded resource 'appsettings.json' was not found. Ensure it's properly embedded in the assembly."); | |
| } | |
| using var istr = resourceStream; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Outside diff range and nitpick comments (7)
YounBotApp.cs (1)
1-4: Remove unused using directiveThe
Microsoft.Extensions.DependencyInjectionnamespace is no longer used after the removal of the Services property.using Lagrange.Core; using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection;Login/QrCodeLogin.cs (2)
12-13: Add XML documentation for better maintainability.Consider adding XML documentation to describe the class purpose and functionality.
+/// <summary> +/// Provides functionality for bot login using either password or QR code authentication. +/// </summary> public static class QrCodeLogin
1-41: Consider security implications of file operations.The code handles sensitive data (keystore and QR codes) and writes them to disk without explicit file permissions or secure deletion.
Consider:
- Using secure file operations with explicit permissions
- Implementing secure deletion for the QR code file
- Encrypting the keystore file
- Moving file paths to secure configuration
Program.cs (1)
Line range hint
29-32: Remove redundant stream closingThe
usingstatements already handle proper disposal of the streams. The explicitClose()calls are unnecessary.using var istr = assm.GetManifestResourceStream("YounBot.Resources.appsettings.json")!; using var temp = File.Create("appsettings.json"); istr.CopyTo(temp); - istr.Close(); - temp.Close();YounBotAppBuilder.cs (3)
19-22: Use properties instead of getter methodsInstead of using explicit getter methods, it's more idiomatic in C# to expose read-only properties. This approach improves code readability and aligns with C# best practices.
Apply this diff to convert getter methods to properties:
-public IConfiguration GetConfiguration() => configuration; -public BotDeviceInfo GetDeviceInfo() => _deviceInfo; -public BotKeystore GetKeystore() => _keystore; -public BotConfig GetConfig() => _botConfig; +public IConfiguration Configuration => configuration; +public BotDeviceInfo DeviceInfo => _deviceInfo; +public BotKeystore Keystore => _keystore; +public BotConfig Config => _botConfig;
29-30: Validate configuration before parsingWhile
Enum.TryParsesafely handles null or invalid strings, it's good practice to ensure that the configuration value is not null before parsing. Additionally, consider logging or handling the case when parsing fails.Modify the code to handle invalid or missing protocol configurations:
-bool isSuccess = Enum.TryParse<Protocols>(configuration["Account:Protocol"], out var protocol); +string protocolConfig = configuration["Account:Protocol"]; +if (!Enum.TryParse<Protocols>(protocolConfig, out var protocol)) +{ + // Handle invalid protocol value, possibly log a warning + protocol = Protocols.Linux; // Default value +}
26-27: Refactor duplicated code for loading configurationsThe logic for loading and initializing
_keystoreand_deviceInfois duplicated. Refactoring this code into a generic method improves maintainability and reduces redundancy.Introduce a generic method to handle loading configurations:
private T LoadConfig<T>(string path, Func<T> defaultFactory) { if (!File.Exists(path)) { var config = defaultFactory(); string json = JsonSerializer.Serialize(config); string? directoryPath = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryPath)) { Directory.CreateDirectory(directoryPath); } File.WriteAllText(path, json); return config; } else { try { return JsonSerializer.Deserialize<T>(File.ReadAllText(path)) ?? defaultFactory(); } catch (Exception) { // Handle exception (e.g., log error) and return default config return defaultFactory(); } } }Then, use this method for
_keystoreand_deviceInfo:- // Existing code to load _keystore + _keystore = LoadConfig<BotKeystore>(keystorePath, () => new BotKeystore()); - // Existing code to load _deviceInfo + _deviceInfo = LoadConfig<BotDeviceInfo>(deviceInfoPath, BotDeviceInfo.GenerateInfo);Also applies to: 42-51, 56-67
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (4)
Login/QrCodeLogin.cs(1 hunks)Program.cs(3 hunks)YounBotApp.cs(1 hunks)YounBotAppBuilder.cs(3 hunks)
🔇 Additional comments (5)
Login/QrCodeLogin.cs (1)
1-10: LGTM! Well-organized imports and namespace.
The imports are properly organized and all appear to be necessary for the functionality.
Program.cs (4)
9-9: LGTM: Import required for QR code login functionality
26-26: Error handling concern still applies
40-44: LGTM: Configuration setup follows best practices
The configuration is properly set up with JSON file and environment variables support.
15-15: Verify impact of removing command-line arguments
The method signature no longer accepts command-line arguments. Please verify if there were any command-line features that need to be preserved.
✅ Verification successful
No impact detected from removing command-line arguments.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for any command-line argument usage in the codebase
rg -l "args\["
rg -l "Environment.GetCommandLineArgs"
rg -l "CommandLineApplication"
Length of output: 86
Script:
#!/bin/bash
# Search for any usage of 'args.' indicating access to command-line arguments
rg -l "args\."
# Search for common command-line parsing libraries or patterns
rg -l "System.CommandLine"
rg -l "CommandLineParser"
rg -l "Parser.Default.ParseArguments"
# Search for any methods that take 'args' as a parameter
rg -l "\.Main\s*\(.*args.*\)"
Length of output: 139
| namespace YounBot; | ||
|
|
||
| public class YounBotApp | ||
| public class YounBotApp(YounBotAppBuilder appBuilder) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add parameter validation and consider interface abstraction
- The
appBuilderparameter should be validated to prevent null reference exceptions - Consider extracting an interface for better testability
-public class YounBotApp(YounBotAppBuilder appBuilder)
+public class YounBotApp(YounBotAppBuilder appBuilder)
+{
+ public YounBotApp(YounBotAppBuilder appBuilder)
+ {
+ ArgumentNullException.ThrowIfNull(appBuilder);
+ Configuration = appBuilder.GetConfiguration();
+ }Consider extracting an interface:
public interface IYounBotApp
{
IConfiguration Configuration { get; }
BotContext? Client { get; set; }
}
public class YounBotApp : IYounBotApp| public readonly IConfiguration Configuration = appBuilder.GetConfiguration(); | ||
| public BotContext? Client; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Restrict mutability of the Client field to ensure thread safety
The Client field is being initialized via BotFactory.Create in Login/QrCodeLogin.cs. To maintain thread safety:
- Make the
Clientproperty's setter internal to prevent external modification. - Ensure that
BotFactory.Createhandles thread-safe initialization.
🔗 Analysis chain
Address potential thread safety and initialization concerns with Client field
The Client field raises several concerns:
- It's publicly mutable without any thread safety mechanisms
- The initialization pattern is unclear
- There's no documentation about when it should be set or what null means
Consider this safer approach:
public readonly IConfiguration Configuration = appBuilder.GetConfiguration();
-public BotContext? Client;
+private BotContext? _client;
+public BotContext? Client
+{
+ get => _client;
+ internal set
+ {
+ ArgumentNullException.ThrowIfNull(value);
+ Interlocked.Exchange(ref _client, value);
+ }
+}Let's check how Client is used across the codebase:
Let's examine how the Client field is initialized in Login/QrCodeLogin.cs:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for Client field usage to understand initialization patterns
rg -l "Client\s*[=\.]" --type csharp
Length of output: 59
Script:
#!/bin/bash
# Find all assignments to Client in Login/QrCodeLogin.cs
rg "^.*Client\s*=.*$" Login/QrCodeLogin.cs
Length of output: 114
| app.Client = BotFactory.Create(config, deviceInfo, keystore); | ||
| var client = app.Client; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for client creation.
The client creation could fail, but there's no error handling in place.
- app.Client = BotFactory.Create(config, deviceInfo, keystore);
- var client = app.Client;
+ try
+ {
+ app.Client = BotFactory.Create(config, deviceInfo, keystore);
+ var client = app.Client;
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException("Failed to create bot client.", ex);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| app.Client = BotFactory.Create(config, deviceInfo, keystore); | |
| var client = app.Client; | |
| try | |
| { | |
| app.Client = BotFactory.Create(config, deviceInfo, keystore); | |
| var client = app.Client; | |
| } | |
| catch (Exception ex) | |
| { | |
| throw new InvalidOperationException("Failed to create bot client.", ex); | |
| } |
| public static async Task Login(YounBotApp app, BotConfig config, BotDeviceInfo deviceInfo, BotKeystore keystore) | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add parameter validation and XML documentation.
The method lacks input validation and documentation which could lead to runtime issues and maintenance difficulties.
+/// <summary>
+/// Attempts to log in to the bot service using password authentication, falling back to QR code if necessary.
+/// </summary>
+/// <param name="app">The YounBot application instance.</param>
+/// <param name="config">The bot configuration.</param>
+/// <param name="deviceInfo">Device information for the bot.</param>
+/// <param name="keystore">The bot keystore.</param>
+/// <returns>A task representing the asynchronous login operation.</returns>
+/// <exception cref="ArgumentNullException">Thrown when any parameter is null.</exception>
public static async Task Login(YounBotApp app, BotConfig config, BotDeviceInfo deviceInfo, BotKeystore keystore)
{
+ ArgumentNullException.ThrowIfNull(app);
+ ArgumentNullException.ThrowIfNull(config);
+ ArgumentNullException.ThrowIfNull(deviceInfo);
+ ArgumentNullException.ThrowIfNull(keystore);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public static async Task Login(YounBotApp app, BotConfig config, BotDeviceInfo deviceInfo, BotKeystore keystore) | |
| { | |
| /// <summary> | |
| /// Attempts to log in to the bot service using password authentication, falling back to QR code if necessary. | |
| /// </summary> | |
| /// <param name="app">The YounBot application instance.</param> | |
| /// <param name="config">The bot configuration.</param> | |
| /// <param name="deviceInfo">Device information for the bot.</param> | |
| /// <param name="keystore">The bot keystore.</param> | |
| /// <returns>A task representing the asynchronous login operation.</returns> | |
| /// <exception cref="ArgumentNullException">Thrown when any parameter is null.</exception> | |
| public static async Task Login(YounBotApp app, BotConfig config, BotDeviceInfo deviceInfo, BotKeystore keystore) | |
| { | |
| ArgumentNullException.ThrowIfNull(app); | |
| ArgumentNullException.ThrowIfNull(config); | |
| ArgumentNullException.ThrowIfNull(deviceInfo); | |
| ArgumentNullException.ThrowIfNull(keystore); |
| client.Invoker.OnBotLogEvent += (_, @event) => { | ||
| Console.WriteLine(@event.ToString()); | ||
| }; | ||
|
|
||
| client.Invoker.OnBotOnlineEvent += (_, @event) => | ||
| { | ||
| Console.WriteLine(@event.ToString()); | ||
| client.UpdateKeystore(); | ||
| File.WriteAllText(app.Configuration["ConfigPath:Keystore"] ?? "keystore.json", JsonSerializer.Serialize(keystore)); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Multiple improvements needed for event handlers.
- Event handlers should be unsubscribable
- File operations need error handling
- Hardcoded fallback path should be configurable
+ private static readonly string DefaultKeystorePath = "keystore.json";
+ private static void OnBotLog(object? sender, BotLogEvent @event)
+ {
+ Console.WriteLine(@event.ToString());
+ }
+
+ private static void OnBotOnline(object? sender, BotOnlineEvent @event, IBotClient client,
+ BotKeystore keystore, IConfiguration configuration)
+ {
+ Console.WriteLine(@event.ToString());
+ client.UpdateKeystore();
+ try
+ {
+ var keystorePath = configuration["ConfigPath:Keystore"] ?? DefaultKeystorePath;
+ File.WriteAllText(keystorePath, JsonSerializer.Serialize(keystore));
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Failed to save keystore: {ex.Message}");
+ }
+ }
+
// In Login method:
- client.Invoker.OnBotLogEvent += (_, @event) => {
- Console.WriteLine(@event.ToString());
- };
+ client.Invoker.OnBotLogEvent += OnBotLog;
- client.Invoker.OnBotOnlineEvent += (_, @event) =>
- {
- Console.WriteLine(@event.ToString());
- client.UpdateKeystore();
- File.WriteAllText(app.Configuration["ConfigPath:Keystore"] ?? "keystore.json",
- JsonSerializer.Serialize(keystore));
- };
+ client.Invoker.OnBotOnlineEvent += (s, e) =>
+ OnBotOnline(s, e, client, keystore, app.Configuration);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| client.Invoker.OnBotLogEvent += (_, @event) => { | |
| Console.WriteLine(@event.ToString()); | |
| }; | |
| client.Invoker.OnBotOnlineEvent += (_, @event) => | |
| { | |
| Console.WriteLine(@event.ToString()); | |
| client.UpdateKeystore(); | |
| File.WriteAllText(app.Configuration["ConfigPath:Keystore"] ?? "keystore.json", JsonSerializer.Serialize(keystore)); | |
| }; | |
| private static readonly string DefaultKeystorePath = "keystore.json"; | |
| private static void OnBotLog(object? sender, BotLogEvent @event) | |
| { | |
| Console.WriteLine(@event.ToString()); | |
| } | |
| private static void OnBotOnline(object? sender, BotOnlineEvent @event, IBotClient client, | |
| BotKeystore keystore, IConfiguration configuration) | |
| { | |
| Console.WriteLine(@event.ToString()); | |
| client.UpdateKeystore(); | |
| try | |
| { | |
| var keystorePath = configuration["ConfigPath:Keystore"] ?? DefaultKeystorePath; | |
| File.WriteAllText(keystorePath, JsonSerializer.Serialize(keystore)); | |
| } | |
| catch (Exception ex) | |
| { | |
| Console.WriteLine($"Failed to save keystore: {ex.Message}"); | |
| } | |
| } | |
| client.Invoker.OnBotLogEvent += OnBotLog; | |
| client.Invoker.OnBotOnlineEvent += (s, e) => | |
| OnBotOnline(s, e, client, keystore, app.Configuration); |
| if (!await app.Client.LoginByPassword()) | ||
| { | ||
| var qrCode = await client.FetchQrCode(); | ||
|
|
||
| if (qrCode != null) | ||
| { | ||
| await File.WriteAllBytesAsync("qrcode.png", qrCode.Value.QrCode); | ||
| await app.Client.LoginByQrCode(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve login flow with error handling, cleanup, and timeouts.
The login flow needs better error handling, QR code file cleanup, and timeout handling.
+ private static readonly string QrCodePath = "qrcode.png";
+ private static readonly TimeSpan LoginTimeout = TimeSpan.FromMinutes(2);
+
// In Login method:
- if (!await app.Client.LoginByPassword())
+ using var cts = new CancellationTokenSource(LoginTimeout);
+ try
{
- var qrCode = await client.FetchQrCode();
-
- if (qrCode != null)
+ if (!await app.Client.LoginByPassword().WaitAsync(cts.Token))
{
- await File.WriteAllBytesAsync("qrcode.png", qrCode.Value.QrCode);
- await app.Client.LoginByQrCode();
+ var qrCode = await client.FetchQrCode().WaitAsync(cts.Token);
+
+ if (qrCode != null)
+ {
+ try
+ {
+ await File.WriteAllBytesAsync(QrCodePath, qrCode.Value.QrCode);
+ await app.Client.LoginByQrCode().WaitAsync(cts.Token);
+ }
+ finally
+ {
+ if (File.Exists(QrCodePath))
+ {
+ File.Delete(QrCodePath);
+ }
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException("Failed to fetch QR code.");
+ }
}
}
+ catch (OperationCanceledException)
+ {
+ throw new TimeoutException("Login operation timed out.");
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!await app.Client.LoginByPassword()) | |
| { | |
| var qrCode = await client.FetchQrCode(); | |
| if (qrCode != null) | |
| { | |
| await File.WriteAllBytesAsync("qrcode.png", qrCode.Value.QrCode); | |
| await app.Client.LoginByQrCode(); | |
| } | |
| } | |
| private static readonly string QrCodePath = "qrcode.png"; | |
| private static readonly TimeSpan LoginTimeout = TimeSpan.FromMinutes(2); | |
| using var cts = new CancellationTokenSource(LoginTimeout); | |
| try | |
| { | |
| if (!await app.Client.LoginByPassword().WaitAsync(cts.Token)) | |
| { | |
| var qrCode = await client.FetchQrCode().WaitAsync(cts.Token); | |
| if (qrCode != null) | |
| { | |
| try | |
| { | |
| await File.WriteAllBytesAsync(QrCodePath, qrCode.Value.QrCode); | |
| await app.Client.LoginByQrCode().WaitAsync(cts.Token); | |
| } | |
| finally | |
| { | |
| if (File.Exists(QrCodePath)) | |
| { | |
| File.Delete(QrCodePath); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| throw new InvalidOperationException("Failed to fetch QR code."); | |
| } | |
| } | |
| } | |
| catch (OperationCanceledException) | |
| { | |
| throw new TimeoutException("Login operation timed out."); | |
| } |
| var appBuilder = new YounBotAppBuilder(configuration); | ||
| var app = appBuilder.Build(); | ||
| // 配置应用程序 | ||
| appBuilder | ||
| .ConfigureBots() | ||
| .ConfigureLogging(logging => logging.AddConsole()); | ||
| appBuilder.ConfigureBots(); | ||
|
|
||
| //登录 | ||
| await QrCodeLogin.Login(app, appBuilder.GetConfig(), appBuilder.GetDeviceInfo(), appBuilder.GetKeystore()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add error handling for login process
The login process should include error handling to gracefully handle potential failures (network issues, invalid QR code, etc.).
var appBuilder = new YounBotAppBuilder(configuration);
var app = appBuilder.Build();
appBuilder.ConfigureBots();
//登录
- await QrCodeLogin.Login(app, appBuilder.GetConfig(), appBuilder.GetDeviceInfo(), appBuilder.GetKeystore());
+ try
+ {
+ await QrCodeLogin.Login(app, appBuilder.GetConfig(), appBuilder.GetDeviceInfo(), appBuilder.GetKeystore());
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Login failed: {ex.Message}");
+ // Consider adding proper logging and graceful shutdown
+ Environment.Exit(1);
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| var appBuilder = new YounBotAppBuilder(configuration); | |
| var app = appBuilder.Build(); | |
| // 配置应用程序 | |
| appBuilder | |
| .ConfigureBots() | |
| .ConfigureLogging(logging => logging.AddConsole()); | |
| appBuilder.ConfigureBots(); | |
| //登录 | |
| await QrCodeLogin.Login(app, appBuilder.GetConfig(), appBuilder.GetDeviceInfo(), appBuilder.GetKeystore()); | |
| var appBuilder = new YounBotAppBuilder(configuration); | |
| var app = appBuilder.Build(); | |
| // 配置应用程序 | |
| appBuilder.ConfigureBots(); | |
| //登录 | |
| try | |
| { | |
| await QrCodeLogin.Login(app, appBuilder.GetConfig(), appBuilder.GetDeviceInfo(), appBuilder.GetKeystore()); | |
| } | |
| catch (Exception ex) | |
| { | |
| Console.WriteLine($"Login failed: {ex.Message}"); | |
| // Consider adding proper logging and graceful shutdown | |
| Environment.Exit(1); | |
| } |
| else | ||
| { | ||
| keystore = JsonSerializer.Deserialize<BotKeystore>(File.ReadAllText(keystorePath)) ?? new BotKeystore(); | ||
| _keystore = JsonSerializer.Deserialize<BotKeystore>(File.ReadAllText(keystorePath)) ?? new BotKeystore(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add exception handling for JSON deserialization
Deserializing JSON files without exception handling can lead to application crashes if the files are corrupt or malformed. Wrap the deserialization calls in try-catch blocks to handle potential exceptions gracefully.
Apply this diff to handle exceptions during deserialization:
For _keystore deserialization:
- _keystore = JsonSerializer.Deserialize<BotKeystore>(File.ReadAllText(keystorePath)) ?? new BotKeystore();
+ try
+ {
+ _keystore = JsonSerializer.Deserialize<BotKeystore>(File.ReadAllText(keystorePath)) ?? new BotKeystore();
+ }
+ catch (Exception ex)
+ {
+ // Log the exception if necessary
+ // Initialize with a new instance to prevent null reference issues
+ _keystore = new BotKeystore();
+ }For _deviceInfo deserialization:
- _deviceInfo = JsonSerializer.Deserialize<BotDeviceInfo>(File.ReadAllText(deviceInfoPath)) ?? BotDeviceInfo.GenerateInfo();
+ try
+ {
+ _deviceInfo = JsonSerializer.Deserialize<BotDeviceInfo>(File.ReadAllText(deviceInfoPath)) ?? BotDeviceInfo.GenerateInfo();
+ }
+ catch (Exception ex)
+ {
+ // Log the exception if necessary
+ // Generate new device info to prevent null reference issues
+ _deviceInfo = BotDeviceInfo.GenerateInfo();
+ }Also applies to: 67-67
| namespace YounBot; | ||
|
|
||
| public sealed class YounBotAppBuilder | ||
| public sealed class YounBotAppBuilder(IConfiguration configuration) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect class declaration syntax
The class declaration public sealed class YounBotAppBuilder(IConfiguration configuration) uses constructor syntax directly in the class declaration, which is invalid for a regular class in C#. This syntax is typically used for records. To define a class with a constructor, you should separate the class declaration from the constructor.
Apply the following changes:
-public sealed class YounBotAppBuilder(IConfiguration configuration)
+public sealed class YounBotAppBuilder
+{
+ private readonly IConfiguration configuration;
+
+ public YounBotAppBuilder(IConfiguration configuration)
+ {
+ this.configuration = configuration;
+ }
+
+ // Rest of the class...📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| public sealed class YounBotAppBuilder(IConfiguration configuration) | |
| public sealed class YounBotAppBuilder | |
| { | |
| private readonly IConfiguration configuration; | |
| public YounBotAppBuilder(IConfiguration configuration) | |
| { | |
| this.configuration = configuration; | |
| } | |
| // Rest of the class... |
| AutoReconnect = bool.Parse(configuration["Account:AutoReconnect"] ?? "true"), | ||
| UseIPv6Network = bool.Parse(configuration["Account:UseIPv6Network"] ?? "false"), | ||
| GetOptimumServer = bool.Parse(configuration["Account:GetOptimumServer"] ?? "true"), | ||
| AutoReLogin = bool.Parse(configuration["Account:AutoReLogin"] ?? "true"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use bool.TryParse to prevent exceptions
Using bool.Parse can throw an exception if the configuration value is not a valid boolean. To make the code more robust, use bool.TryParse and provide default values when parsing fails.
Apply this diff to safely parse boolean configuration values:
-AutoReconnect = bool.Parse(configuration["Account:AutoReconnect"] ?? "true"),
+if (!bool.TryParse(configuration["Account:AutoReconnect"], out var autoReconnect))
+{
+ autoReconnect = true; // Default value
+}
+AutoReconnect = autoReconnect;
-UseIPv6Network = bool.Parse(configuration["Account:UseIPv6Network"] ?? "false"),
+if (!bool.TryParse(configuration["Account:UseIPv6Network"], out var useIPv6Network))
+{
+ useIPv6Network = false; // Default value
+}
+UseIPv6Network = useIPv6Network;
-GetOptimumServer = bool.Parse(configuration["Account:GetOptimumServer"] ?? "true"),
+if (!bool.TryParse(configuration["Account:GetOptimumServer"], out var getOptimumServer))
+{
+ getOptimumServer = true; // Default value
+}
+GetOptimumServer = getOptimumServer;
-AutoReLogin = bool.Parse(configuration["Account:AutoReLogin"] ?? "true"),
+if (!bool.TryParse(configuration["Account:AutoReLogin"], out var autoReLogin))
+{
+ autoReLogin = true; // Default value
+}
+AutoReLogin = autoReLogin;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| AutoReconnect = bool.Parse(configuration["Account:AutoReconnect"] ?? "true"), | |
| UseIPv6Network = bool.Parse(configuration["Account:UseIPv6Network"] ?? "false"), | |
| GetOptimumServer = bool.Parse(configuration["Account:GetOptimumServer"] ?? "true"), | |
| AutoReLogin = bool.Parse(configuration["Account:AutoReLogin"] ?? "true"), | |
| if (!bool.TryParse(configuration["Account:AutoReconnect"], out var autoReconnect)) | |
| { | |
| autoReconnect = true; // Default value | |
| } | |
| AutoReconnect = autoReconnect, | |
| if (!bool.TryParse(configuration["Account:UseIPv6Network"], out var useIPv6Network)) | |
| { | |
| useIPv6Network = false; // Default value | |
| } | |
| UseIPv6Network = useIPv6Network, | |
| if (!bool.TryParse(configuration["Account:GetOptimumServer"], out var getOptimumServer)) | |
| { | |
| getOptimumServer = true; // Default value | |
| } | |
| GetOptimumServer = getOptimumServer, | |
| if (!bool.TryParse(configuration["Account:AutoReLogin"], out var autoReLogin)) | |
| { | |
| autoReLogin = true; // Default value | |
| } | |
| AutoReLogin = autoReLogin, |
Summary by CodeRabbit
New Features
Bug Fixes
Chores