-
Notifications
You must be signed in to change notification settings - Fork 19
Dev #55
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
Reviewer's GuideRefactors network and timeout handling in the napcat adapter utilities, adjusts forward-message return semantics and error handling, and updates the README to document dev/classical branch stability and usage guidance. Sequence diagram for updated get_image_base64 network handlingsequenceDiagram
participant Caller
participant Utils as NapcatUtils
participant Aiohttp as aiohttp_ClientSession
participant Remote as RemoteServer
Caller->>Utils: get_image_base64(url)
activate Utils
Utils->>Aiohttp: create ClientSession()
activate Aiohttp
Utils->>Aiohttp: session.get(url, timeout=10)
Aiohttp->>Remote: HTTP GET url
Remote-->>Aiohttp: HTTP response
Aiohttp-->>Utils: response
alt response.status != 200
Utils-->>Caller: raise Exception HTTP_Error_status
else response.status == 200
Utils->>Aiohttp: response.read()
Aiohttp-->>Utils: image_bytes
Utils-->>Caller: base64_b64encode(image_bytes)
end
deactivate Aiohttp
deactivate Utils
opt any_exception
Utils->>Utils: log error 图片下载失败
Utils-->>Caller: re_raise_exception
end
Sequence diagram for updated get_forward_message error handling and return typesequenceDiagram
participant Caller
participant Utils as NapcatUtils
participant Adapter as NapcatAdapter
Caller->>Utils: get_forward_message(raw_message, adapter)
activate Utils
Utils->>Utils: extract forward_message_data from raw_message
alt forward_message_data empty
Utils->>Utils: log warning 转发消息内容为空
Utils-->>Caller: None
else forward_message_data present
Utils->>Adapter: get_msg(forward_id)
activate Adapter
Adapter-->>Utils: response or timeout or error
deactivate Adapter
alt response is None
Utils->>Utils: log error 获取转发消息失败,返回值为空
Utils-->>Caller: [{sender:{nickname:系统}, message:[{type:text, data:[获取转发消息失败]}]}]
else adapter timeout
Utils->>Utils: log error 获取转发消息超时
Utils-->>Caller: [{sender:{nickname:系统}, message:[{type:text, data:[获取转发消息超时]}]}]
else adapter exception
Utils->>Utils: log error 获取转发消息失败
Utils-->>Caller: [{sender:{nickname:系统}, message:[{type:text, data:[获取转发消息失败_with_reason]}]}]
else response ok
Utils->>Utils: response_data = (response.data or {})
alt response_data empty
Utils->>Utils: log warning 转发消息内容为空或获取失败
Utils-->>Caller: None
else response_data present
Utils->>Utils: log debug 转发消息原始格式
Utils-->>Caller: response_data as list_of_message_nodes
end
end
deactivate Utils
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
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.
Hey - I've found 3 issues, and left some high level feedback:
- In
get_image_base64, consider reusing anaiohttp.ClientSessioninstead of creating a new session on every call to avoid unnecessary connection overhead and improve performance under load. get_forward_messagenow usually returns alist[dict](including for error cases) but still returnsNonewhenresponse_datais empty; aligning all error/empty cases to a consistent list-based return shape would simplify caller handling and reduce the need for extraNonechecks.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `get_image_base64`, consider reusing an `aiohttp.ClientSession` instead of creating a new session on every call to avoid unnecessary connection overhead and improve performance under load.
- `get_forward_message` now usually returns a `list[dict]` (including for error cases) but still returns `None` when `response_data` is empty; aligning all error/empty cases to a consistent list-based return shape would simplify caller handling and reduce the need for extra `None` checks.
## Individual Comments
### Comment 1
<location> `src/plugins/built_in/napcat_adapter/src/handlers/utils.py:238-239` </location>
<code_context>
- raise Exception(f"HTTP Error: {response.status}")
- image_bytes = response.data
- return base64.b64encode(image_bytes).decode("utf-8")
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, timeout=10) as response:
+ if response.status != 200:
+ raise Exception(f"HTTP Error: {response.status}")
</code_context>
<issue_to_address>
**suggestion:** Consider reusing an aiohttp.ClientSession and configuring SSL/timeouts explicitly instead of creating a new session per call.
Creating a new `ClientSession` on every `get_image_base64` call adds unnecessary overhead and can trigger aiohttp warnings. Prefer a shared or injected session, configured once with `ClientTimeout` and a `TCPConnector` (including SSL options), so you can preserve any required relaxed SSL/cipher/TLS settings while keeping the async API.
Suggested implementation:
```python
import aiohttp
# Shared HTTP client session for outbound requests from this module.
# NOTE: This avoids creating a new ClientSession per call, which is inefficient
# and may trigger aiohttp warnings. Configure timeout/SSL/connector here.
_HTTP_SESSION: aiohttp.ClientSession | None = None
async def get_http_session() -> aiohttp.ClientSession:
"""Get (or lazily create) a shared aiohttp ClientSession.
Centralizes timeout/SSL/connector configuration so callers do not need to
create their own sessions and we can preserve any custom TLS settings.
"""
global _HTTP_SESSION
if _HTTP_SESSION is None or _HTTP_SESSION.closed:
timeout = aiohttp.ClientTimeout(total=10)
connector = aiohttp.TCPConnector(
# Set SSL options explicitly; adjust as needed for your environment.
# ssl=None keeps default verification; set ssl=False to disable it.
ssl=None,
# You can tune connection limits here if needed.
limit=100,
)
_HTTP_SESSION = aiohttp.ClientSession(
timeout=timeout,
connector=connector,
)
return _HTTP_SESSION
```
```python
# sourcery skip: raise-specific-error
"""下载图片/视频并返回Base64"""
logger.debug(f"下载图片: {url}")
try:
session = await get_http_session()
async with session.get(url) as response:
if response.status != 200:
raise Exception(f"HTTP Error: {response.status}")
image_bytes = await response.read()
return base64.b64encode(image_bytes).decode("utf-8")
except Exception as e:
logger.error(f"图片下载失败: {e!s}")
```
If this function is not already declared as `async`, it must be updated to `async def ...` to allow `await get_http_session()`.
If your project has a centralized lifecycle management (startup/shutdown hooks), you may also want to add logic there to gracefully close `_HTTP_SESSION` (e.g. `await _HTTP_SESSION.close()` on shutdown) rather than relying on process exit.
</issue_to_address>
### Comment 2
<location> `src/plugins/built_in/napcat_adapter/src/handlers/utils.py:375-381` </location>
<code_context>
async def get_forward_message(
raw_message: dict, *, adapter: "NapcatAdapter | None" = None
-) -> dict[str, Any] | None:
</code_context>
<issue_to_address>
**question (bug_risk):** The return type of get_forward_message is now a list, but some branches still return None; consider making the result shape more consistent.
The function now sometimes returns a synthetic single-element list on error/timeout, but still uses `None` when `response_data` is falsy ("转发消息内容为空或获取失败"). This forces callers to handle three shapes: a normal list from the API, a synthetic error list, and `None`. Consider standardizing on either a list for all non-success cases (e.g., a system message element) or consistently using `None` for all failures, and ensure this matches existing caller expectations to avoid subtle logic errors.
</issue_to_address>
### Comment 3
<location> `README.md:36` </location>
<code_context>
+> **分支状态说明**
+>
+> - `dev` 分支当前用于架构重构与大规模改动,功能不稳定,无法保证可用性。
+> - 现行可用的稳定版本已迁移至 `classical` 分支,并在该分支持续维护。
+> - 如需稳定使用,请切换到 `classical` 分支:
+>
</code_context>
<issue_to_address>
**nitpick (typo):** Consider adding “上” in “并在该分支持续维护” for more natural written Chinese.
This matches standard written usage and improves readability.
```suggestion
> - 现行可用的稳定版本已迁移至 `classical` 分支,并在该分支上持续维护。
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| async with aiohttp.ClientSession() as session: | ||
| async with session.get(url, timeout=10) as response: |
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.
suggestion: Consider reusing an aiohttp.ClientSession and configuring SSL/timeouts explicitly instead of creating a new session per call.
Creating a new ClientSession on every get_image_base64 call adds unnecessary overhead and can trigger aiohttp warnings. Prefer a shared or injected session, configured once with ClientTimeout and a TCPConnector (including SSL options), so you can preserve any required relaxed SSL/cipher/TLS settings while keeping the async API.
Suggested implementation:
import aiohttp
# Shared HTTP client session for outbound requests from this module.
# NOTE: This avoids creating a new ClientSession per call, which is inefficient
# and may trigger aiohttp warnings. Configure timeout/SSL/connector here.
_HTTP_SESSION: aiohttp.ClientSession | None = None
async def get_http_session() -> aiohttp.ClientSession:
"""Get (or lazily create) a shared aiohttp ClientSession.
Centralizes timeout/SSL/connector configuration so callers do not need to
create their own sessions and we can preserve any custom TLS settings.
"""
global _HTTP_SESSION
if _HTTP_SESSION is None or _HTTP_SESSION.closed:
timeout = aiohttp.ClientTimeout(total=10)
connector = aiohttp.TCPConnector(
# Set SSL options explicitly; adjust as needed for your environment.
# ssl=None keeps default verification; set ssl=False to disable it.
ssl=None,
# You can tune connection limits here if needed.
limit=100,
)
_HTTP_SESSION = aiohttp.ClientSession(
timeout=timeout,
connector=connector,
)
return _HTTP_SESSION # sourcery skip: raise-specific-error
"""下载图片/视频并返回Base64"""
logger.debug(f"下载图片: {url}")
try:
session = await get_http_session()
async with session.get(url) as response:
if response.status != 200:
raise Exception(f"HTTP Error: {response.status}")
image_bytes = await response.read()
return base64.b64encode(image_bytes).decode("utf-8")
except Exception as e:
logger.error(f"图片下载失败: {e!s}")If this function is not already declared as async, it must be updated to async def ... to allow await get_http_session().
If your project has a centralized lifecycle management (startup/shutdown hooks), you may also want to add logic there to gracefully close _HTTP_SESSION (e.g. await _HTTP_SESSION.close() on shutdown) rather than relying on process exit.
|
|
||
| async def get_forward_message( | ||
| raw_message: dict, *, adapter: "NapcatAdapter | None" = None | ||
| ) -> dict[str, Any] | None: | ||
| ) -> list[dict[str, Any]] | None: | ||
| forward_message_data: dict = raw_message.get("data", {}) | ||
| if not forward_message_data: | ||
| logger.warning("转发消息内容为空") |
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.
question (bug_risk): The return type of get_forward_message is now a list, but some branches still return None; consider making the result shape more consistent.
The function now sometimes returns a synthetic single-element list on error/timeout, but still uses None when response_data is falsy ("转发消息内容为空或获取失败"). This forces callers to handle three shapes: a normal list from the API, a synthetic error list, and None. Consider standardizing on either a list for all non-success cases (e.g., a system message element) or consistently using None for all failures, and ensure this matches existing caller expectations to avoid subtle logic errors.
| > **分支状态说明** | ||
| > | ||
| > - `dev` 分支当前用于架构重构与大规模改动,功能不稳定,无法保证可用性。 | ||
| > - 现行可用的稳定版本已迁移至 `classical` 分支,并在该分支持续维护。 |
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.
nitpick (typo): Consider adding “上” in “并在该分支持续维护” for more natural written Chinese.
This matches standard written usage and improves readability.
| > - 现行可用的稳定版本已迁移至 `classical` 分支,并在该分支持续维护。 | |
| > - 现行可用的稳定版本已迁移至 `classical` 分支,并在该分支上持续维护。 |
Summary by Sourcery
Update network handling for media and forwarded messages and clarify branch stability in the README.
Bug Fixes:
Enhancements:
Documentation: