Skip to content

Conversation

@lxdklp
Copy link
Contributor

@lxdklp lxdklp commented Aug 19, 2025

修复了issues #757
加入了对于中文Windows GBK解码,当utf8乱码时回退GBK
截屏2025-08-19 18 13 24

Summary by Sourcery

Detect malformed UTF-8 in server status output and fallback to GBK decoding using flutter_gbk2utf8, update decoding logic, and add necessary dependency and DevTools configuration.

New Features:

  • Add fallback to GBK decoding for command outputs when UTF-8 decoding fails to support Chinese Windows environments

Bug Fixes:

Enhancements:

  • Improve detection of malformed UTF-8 by checking for replacement characters and substrings before fallback

Build:

  • Add flutter_gbk2utf8 dependency for GBK decoding

Chores:

  • Include devtools_options.yaml for Dart & Flutter DevTools configuration

@sourcery-ai
Copy link

sourcery-ai bot commented Aug 19, 2025

Reviewer's Guide

Enhance SSH command output handling by implementing a GBK fallback decoding strategy with error logging, and update project dependencies and configuration accordingly.

Sequence diagram for SSH command output decoding with GBK fallback

sequenceDiagram
    participant ServerProvider
    participant SSHClient
    participant Loggers
    ServerProvider->>SSHClient: run(ShellFunc.status.exec(...))
    SSHClient-->>ServerProvider: execResult (bytes)
    ServerProvider->>ServerProvider: Try utf8.decode(execResult)
    alt UTF-8 decoding fails or contains invalid chars
        ServerProvider->>Loggers: Log warning (UTF8 decoding failed)
        ServerProvider->>ServerProvider: Try gbk.decode(execResult)
        alt GBK decoding fails
            ServerProvider->>Loggers: Log warning (GBK decoding failed)
            ServerProvider->>ServerProvider: Set raw = 'decode failed...'
        else GBK decoding succeeds
            ServerProvider->>ServerProvider: Set raw = gbk-decoded string
        end
    else UTF-8 decoding succeeds
        ServerProvider->>ServerProvider: Set raw = utf8-decoded string
    end
Loading

Class diagram for updated ServerProvider SSH output decoding

classDiagram
    class ServerProvider {
        +Future<void> getStatus(...)
        -String raw
        -List<String> segments
    }
    class Loggers {
        +app: Logger
    }
    class gbk {
        +decode(List<int>): String
    }
    ServerProvider --> Loggers : uses
    ServerProvider --> gbk : uses
    ServerProvider --> SSHClient : uses
    class SSHClient {
        +run(command): List<int>
    }
Loading

File-Level Changes

Change Details Files
Implement GBK fallback decoding for SSH command outputs
  • Wrap SSH exec call to capture raw byte output
  • Try UTF-8 decode with allowMalformed and detect replacement characters
  • Flag GBK fallback when UTF-8 decoding yields errors or malformed runes
  • Perform GBK decoding on fallback and catch related exceptions
  • Log warnings for both UTF-8 and GBK decoding failures
  • Refactor segment splitting to remove null checks and handle empty cases
lib/data/provider/server.dart
Add flutter_gbk2utf8 dependency
  • Declare flutter_gbk2utf8: ^1.0.1 in pubspec.yaml dependencies
pubspec.yaml
Include DevTools configuration file
  • Add devtools_options.yaml for Dart & Flutter DevTools extension settings
devtools_options.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Consider extracting the GBK/UTF-8 decoding fallback logic into a helper function to improve readability and reuse.
  • Remove the flutter/material.dart import from the server provider since it’s not used in this context.
  • Use the existing Logger instead of debugPrint for error output to keep logging consistent across the app.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider extracting the GBK/UTF-8 decoding fallback logic into a helper function to improve readability and reuse.
- Remove the flutter/material.dart import from the server provider since it’s not used in this context.
- Use the existing Logger instead of debugPrint for error output to keep logging consistent across the app.

## Individual Comments

### Comment 1
<location> `lib/data/provider/server.dart:469` </location>
<code_context>
+              Loggers.app.warning('GBK decoding failed', e2);
+            }
+          }
+          raw = rawStr;
+        } else {
+          raw = execResult.toString();
</code_context>

<issue_to_address>
Potential for raw to be null if both decoding attempts fail.

If decoding fails for both encodings, rawStr stays null and may cause issues later. Please add explicit handling or a fallback to prevent silent errors.
</issue_to_address>

### Comment 2
<location> `lib/data/provider/server.dart:496` </location>
<code_context>
       sv.status.err = SSHErr(type: SSHErrType.getStatus, message: e.toString());
       _setServerState(s, ServerConn.failed);
       Loggers.app.warning('Get status from ${spi.name} failed', e);
+      debugPrint('错误 $raw');

       // Update SSH session status to disconnected on status error
</code_context>

<issue_to_address>
Consider removing or gating debugPrint for production builds.

Debug statements like debugPrint should be removed or conditionally executed to avoid cluttering production logs.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

sv.status.err = SSHErr(type: SSHErrType.getStatus, message: e.toString());
_setServerState(s, ServerConn.failed);
Loggers.app.warning('Get status from ${spi.name} failed', e);
debugPrint('错误 $raw');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Consider removing or gating debugPrint for production builds.

Debug statements like debugPrint should be removed or conditionally executed to avoid cluttering production logs.

@lxdklp
Copy link
Contributor Author

lxdklp commented Aug 19, 2025

未测试英文Windows的兼容性,英文Windows似乎是ASCII?

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


The compatibility of English Windows is not tested, and English Windows seems to be ASCII?

@lollipopkit
Copy link
Owner

Can you apply the code recommendations from sourcery ai?

Thanks your contribution.

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


OK, sorry to see it

@lxdklp
Copy link
Contributor Author

lxdklp commented Aug 19, 2025

不好意思,我才看到sourcery ai的更改。请问是点击为 resolved 状态就行了还是修改完重新pr

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


Sorry, I saw the changes to sourcery ai. Is it OK to just click to resolved status or to modify it and re-pr

@lollipopkit
Copy link
Owner

提交 commit 到你的 fork 就好,然后点击 resolve

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


Just submit commit to your fork, and click resolve

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


The code has been modified to remove debugging during debugging, and ensure that the returned raw data is non-empty. When the data cannot be decoded, the user is prompted to submit the log for feedback.

@lxdklp
Copy link
Contributor Author

lxdklp commented Aug 20, 2025

已修改代码,将调试期间使用的debugprint去除,并且确保了返回时的数据为非空数据,当utf8与gbk均无法正确解码时提示用户提交日记进行反馈

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


The code has been modified to remove the debugprint used during debugging, and ensure that the data returned is non-empty. When both utf8 and gbk cannot be decoded correctly, the user is prompted to submit a diary for feedback.

@lollipopkit
Copy link
Owner

@sourcery-ai review

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Remove devtools_options.yaml from the commit as it’s an IDE-specific config and not relevant to the GBK decoding fix.
  • Consider extracting the UTF-8/GBK decoding fallback logic into a separate utility or extension method for improved readability and easier testing.
  • Handle the null execResult case explicitly instead of calling toString() (which yields "null"), to avoid confusion when parsing downstream.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Remove devtools_options.yaml from the commit as it’s an IDE-specific config and not relevant to the GBK decoding fix.
- Consider extracting the UTF-8/GBK decoding fallback logic into a separate utility or extension method for improved readability and easier testing.
- Handle the null execResult case explicitly instead of calling toString() (which yields "null"), to avoid confusion when parsing downstream.

## Individual Comments

### Comment 1
<location> `lib/data/provider/server.dart:454` </location>
<code_context>
+          bool needGbk = false;
+          try {
+            rawStr = utf8.decode(execResult, allowMalformed: true);
+            if (rawStr.runes.where((c) => c == 0xfffd).length > 5 || rawStr.contains('��')) {
+              needGbk = true;
+            }
</code_context>

<issue_to_address>
Threshold for malformed UTF-8 detection may need adjustment.

The threshold for replacement characters may not suit all cases. Consider making it configurable or clarifying why this value was chosen.

Suggested implementation:

```
          // The threshold for malformed UTF-8 detection is configurable via malformedThreshold.
          try {
            rawStr = utf8.decode(execResult, allowMalformed: true);
            final malformedCount = rawStr.runes.where((c) => c == 0xfffd).length;
            if (malformedCount > malformedThreshold || rawStr.contains('��')) {
              needGbk = true;
            }

```

1. Add an integer parameter `malformedThreshold` (with a default value of 5) to the containing function or class.
2. Pass `malformedThreshold` where this function is called, if you want to override the default.
3. Document the parameter in the function/class docstring to clarify its purpose.
</issue_to_address>

### Comment 2
<location> `lib/data/provider/server.dart:463` </location>
<code_context>
+          }
+          if (needGbk) {
+            try {
+              rawStr = gbk.decode(execResult);
+            } catch (e2) {
+              Loggers.app.warning('GBK decoding failed', e2);
</code_context>

<issue_to_address>
GBK decoding fallback is a good idea, but may mask other encoding issues.

Consider logging the original bytes or adding more context to error messages to help diagnose cases where both UTF-8 and GBK decoding fail.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
            } catch (e2) {
              Loggers.app.warning('GBK decoding failed', e2);
              rawStr = 'decode failed, please submit the issues with the log';
            }
=======
            } catch (e2) {
              Loggers.app.warning(
                'GBK decoding failed after UTF8 fallback. Original bytes: ${execResult}',
                e2,
              );
              rawStr = 'decode failed, please submit the issues with the log. Original bytes: ${execResult}';
            }
>>>>>>> REPLACE

</suggested_fix>

### Comment 3
<location> `lib/data/provider/server.dart:469` </location>
<code_context>
+              rawStr = 'decode failed, please submit the issues with the log';
+            }
+          }
+          raw = rawStr ?? 'decode failed, please submit the issues with the log';
+        } else {
+          raw = execResult.toString();
</code_context>

<issue_to_address>
Error message could be more actionable for users.

Specify which log users should submit and provide instructions or a path to help them locate it.

Suggested implementation:

```
              rawStr = 'Decode failed. Please submit an issue and attach the application log file (see Help > View Log File in the menu) for troubleshooting.';

```

```
          raw = rawStr ?? 'Decode failed. Please submit an issue and attach the application log file (see Help > View Log File in the menu) for troubleshooting.';

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@lxdklp
Copy link
Contributor Author

lxdklp commented Aug 20, 2025

修改了判断gbk方式,只要检测到�就尝试gbk解码,并且当无法解码时将值设定为null由后面gui显示错误,错误信息与其他报错信息格式相似

@Issues-translate-bot
Copy link

Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿


Modified the method of judging gbk, try gbk decoding as long as it is detected, and set the value to null when decoding cannot be decoded. The error message is similar to other error message formats.

@lollipopkit
Copy link
Owner

@claude review

@claude
Copy link

claude bot commented Aug 21, 2025

Claude finished @lollipopkit's task —— View job


Code Review for PR #863 - GBK Decoding Fallback

Todo List:

  • Read repository guidelines (CLAUDE.md) - No repo-specific guidelines found
  • Examine the main code changes in lib/data/provider/server.dart
  • Review dependency changes in pubspec.yaml
  • Check if Sourcery AI feedback has been addressed
  • Analyze error handling and logging implementation
  • Provide comprehensive review feedback

🚨 Critical Issue Found

After thoroughly analyzing the repository, I cannot locate PR #863 or any GBK decoding implementation. The current codebase is on the main branch and contains no evidence of:

  1. Missing GBK Implementation: No GBK fallback decoding logic exists in /lib/data/provider/server.dart
  2. Missing Dependency: flutter_gbk2utf8 dependency is not present in pubspec.yaml
  3. Missing Files: No devtools_options.yaml file exists
  4. Missing Branch: No PR branch or commits reference this work

Current Encoding Handling

The codebase currently uses standard UTF-8 string conversion without any encoding fallback:

// In lib/core/extension/ssh_client.dart
return (session, result.takeBytes().string);

// In lib/data/provider/server.dart  
raw = await sv.client?.run(ShellFunc.status.exec(...)).string;

This would indeed cause garbled text on Chinese Windows systems using GBK encoding.

Recommendation

It appears this PR may not have been properly pushed to the repository, or I'm reviewing the wrong branch. Please verify:

  1. Branch Status: Confirm the PR branch exists and contains the expected changes
  2. Push Status: Ensure all commits with GBK implementation were pushed to the remote branch
  3. Repository: Verify this is the correct repository fork containing the changes

If the implementation exists elsewhere, I'd be happy to review it once the proper branch is available.


@lollipopkit lollipopkit changed the title fix #757 fix: GBK decoding fallback Aug 21, 2025
@lollipopkit lollipopkit merged commit 24fd4b7 into lollipopkit:main Aug 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

无法连接到windows ssh服务器

3 participants