Skip to content

refactor(mcsmapi): 重构 API 类方法并优化模型定义#14

Merged
molanp merged 1 commit intomainfrom
refactor
Aug 15, 2025
Merged

refactor(mcsmapi): 重构 API 类方法并优化模型定义#14
molanp merged 1 commit intomainfrom
refactor

Conversation

@molanp
Copy link
Copy Markdown
Owner

@molanp molanp commented Aug 15, 2025

  • 将 API 类中的实例方法改为静态方法,简化使用
  • 优化模型定义,提高代码可读性和维护性
  • 新增 common 模型模块,用于定义通用的模型结构
  • 调整文件列表和 Docker 相关模型结构,增强数据表达能力

Sourcery 总结

重构 API 类以使用静态方法,并通过整合通用模式、升级到 Pydantic v2 规范、引入枚举类型用于关键字段以及扩展模型结构来现代化所有 Pydantic 模型

新功能:

  • 添加一个通用模型模块,包含共享的 CpuMemChart、ProcessInfo 和 InstanceInfo 定义
  • 引入多种 IntEnum 类型 (CRLFType, Status, UserPermission, FileType),以增强模型字段的类型强度

改进:

  • 将所有 API 类实例方法转换为静态方法,以简化使用
  • 将模型定义升级到 Pydantic v2,使用 model_dump()、现代类型注解和扩展字段,以实现更丰富的数据表示
  • 重构并整合模型定义,将共享模式移至 mcsmapi/models/common.py

构建:

  • 在 pyproject.toml 中要求 Python >=3.10 和 Pydantic >=2.0
Original summary in English

Summary by Sourcery

Refactor API classes to use static methods and modernize all Pydantic models by consolidating common schemas, upgrading to Pydantic v2 conventions, introducing enums for key fields, and expanding model structures

New Features:

  • Add a common models module with shared CpuMemChart, ProcessInfo, and InstanceInfo definitions
  • Introduce various IntEnum types (CRLFType, Status, UserPermission, FileType) for stronger typing in model fields

Enhancements:

  • Convert all API class instance methods to static methods for simplified usage
  • Upgrade model definitions to Pydantic v2 with model_dump(), modern type annotations, and extended fields for richer data representation
  • Refactor and consolidate model definitions, moving shared schemas into mcsmapi/models/common.py

Build:

  • Require Python >=3.10 and Pydantic >=2.0 in pyproject.toml

- 将 API 类中的实例方法改为静态方法,简化使用
- 优化模型定义,提高代码可读性和维护性
- 新增 common 模型模块,用于定义通用的模型结构
- 调整文件列表和 Docker 相关模型结构,增强数据表达能力
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Aug 15, 2025

审阅者指南

此 PR 将所有 API 类方法重构为静态方法,将 Pydantic 模型定义升级到 v2 兼容性,集中管理共享模型,丰富数据模型中的类型注解和枚举使用,并更新项目要求以支持 Python>=3.10 和 Pydantic>=2.0。

新公共模型及其用法的实体关系图

erDiagram
    DaemonModel ||--o| CpuMemChart : has
    DaemonModel ||--o| ProcessInfo : has
    DaemonModel ||--o| InstanceInfo : has
    OverviewModel ||--o| CpuMemChart : has
    OverviewModel ||--o| InstanceInfo : has
    OverviewModel ||--o| ProcessInfo : has
Loading

重构后的静态方法 API 类的类图

classDiagram
    class Instance {
        +static search(daemonId, page, page_size, keyword, type, tag)
        +static detail(daemonId, uuid)
        +static create(daemonId, config)
        +static updateConfig(daemonId, uuid, config)
        +static delete(daemonId, uuids, deleteFile)
        +static start(daemonId, uuid)
        +static stop(daemonId, uuid)
        +static restart(daemonId, uuid)
        +static kill(daemonId, uuid)
        +static batchOperation(instances, operation)
        +static update(daemonId, uuid)
        +static command(daemonId, uuid, command)
        +static get_output(daemonId, uuid, size)
        +static reinstall(daemonId, uuid, targetUrl, title, description)
    }
    class File {
        +static show(daemonId, uuid, target, page, page_size, file_name)
        +static content(daemonId, uuid, target)
        +static update(daemonId, uuid, target, text)
        +static download(daemonId, uuid, file_name)
        +static upload(daemonId, uuid, file, upload_dir)
        +static copy(daemonId, uuid, copy_map)
        +static copyOne(daemonId, uuid, source, target)
        +static move(daemonId, uuid, copy_map)
        +static moveOne(daemonId, uuid, source, target)
        +static rename(daemonId, uuid, source, new_name)
        +static zip(daemonId, uuid, source, targets)
        +static unzip(daemonId, uuid, source, target, code)
        +static delete(daemonId, uuid, targets)
        +static createFile(daemonId, uuid, target)
        +static createFloder(daemonId, uuid, target)
    }
    class Daemon {
        +static show()
        +static system()
        +static add(config)
        +static delete(daemonId)
        +static link(daemonId)
        +static update(daemonId, config)
    }
    class Image {
        +static images(daemonId)
        +static containers(daemonId)
        +static network(daemonId)
        +static add(daemonId, dockerFile, name, tag)
        +static progress(daemonId)
    }
    class User {
        +static search(username, page, page_size, role)
        +static create(username, password, permission)
        +static update(uuid, config)
        +static delete(uuids)
    }
    class Overview {
        +static init()
    }
Loading

更新后的 InstanceConfig 和相关枚举的类图

classDiagram
    class InstanceConfig {
        nickname: str
        startCommand: str
        stopCommand: str
        cwd: str
        ie: str
        oe: str
        createDatetime: int
        lastDatetime: int
        type: str
        tag: list[str]
        endTime: int | None
        fileCode: str
        processType: str
        updateCommand: str
        actionCommandlist: list[str]
        crlf: CRLFType
        docker: DockerConfig
        enableRcon: bool
        rconPassword: str
        rconPort: int
        rconIp: str
        terminalOption: TerminalOption
        eventTask: EventTask
        pingConfig: PingConfig
        runAs: str
    }
    class CRLFType {
        LF
        CR
        CRLF
    }
    class Status {
        BUSY
        STOP
        STOPPING
        STARTING
        RUNNING
    }
    InstanceConfig --> CRLFType
    InstanceConfig --> DockerConfig
    InstanceConfig --> TerminalOption
    InstanceConfig --> EventTask
    InstanceConfig --> PingConfig
Loading

新公共模型模块的类图

classDiagram
    class CpuMemChart {
        cpu: float
        mem: float
    }
    class ProcessInfo {
        cpu: int
        memory: int
        cwd: str
    }
    class InstanceInfo {
        running: int
        total: int
    }
Loading

更新后的 FileItem 和 FileType 枚举的类图

classDiagram
    class FileItem {
        name: str
        size: int
        time: str
        mode: int
        type: FileType
        daemonId: str
        uuid: str
        target: str
        file_name: str
    }
    class FileType {
        FOLDER
        FILE
    }
    FileItem --> FileType
Loading

更新后的 UserModel 和 UserPermission 枚举的类图

classDiagram
    class UserModel {
        uuid: str
        userName: str
        passWord: str
        passWordType: int
        salt: str
        permission: UserPermission
        registerTime: str
        loginTime: str
        apiKey: str
        isInit: bool
        secret: str
        open2FA: bool
        instances: list[UserInstancesList]
    }
    class UserPermission {
        BANNED
        USER
        ADMIN
    }
    UserModel --> UserPermission
Loading

文件级变更

变更 详细信息 文件
将 API 实例方法转换为静态方法
  • 为所有 API 方法添加 @staticmethod 装饰器
  • 将 Instance().method 调用替换为 Instance.method
  • 更新客户端入口点(使用 Overview.init 而非 Overview())
mcsmapi/apis/file.py
mcsmapi/apis/instance.py
mcsmapi/apis/daemon.py
mcsmapi/apis/image.py
mcsmapi/apis/user.py
mcsmapi/apis/overview.py
mcsmapi/__init__.py
将 Pydantic 模型迁移到 v2 规范
  • 将 BaseModel.dict() 替换为 BaseModel.model_dump()
  • fields.keys() 的使用替换为 model_fields.keys()
  • 更新基于字典的实例化,以使用 model_dump 和 model_fields
mcsmapi/models/instance.py
mcsmapi/models/daemon.py
mcsmapi/models/user.py
提取并重用公共模型定义
  • 创建 mcsmapi/models/common.py,包含 CpuMemChart, ProcessInfo, InstanceInfo
  • 在 daemon.py 和 overview.py 中导入公共模型
  • 从源模块中删除重复的模型类
mcsmapi/models/common.py
mcsmapi/models/daemon.py
mcsmapi/models/overview.py
使用更丰富的类型和枚举增强数据模型
  • 将 typing.List/Optional/Union 替换为 Python 3.10 原生类型和 Literal
  • 为 CRLFType, Status, UserPermission, FileType 添加 IntEnum 类
  • 为 DockerConfig, FileItem 和其他模型增加额外字段
mcsmapi/models/instance.py
mcsmapi/models/image.py
mcsmapi/models/file.py
mcsmapi/models/user.py
更新项目配置以支持现代 Python 和 Pydantic
  • 将 requires-python 设置为 ">=3.10"
  • 将 pydantic 锁定为 ">=2.0.0"
pyproject.toml

提示和命令

与 Sourcery 互动

  • 触发新审阅: 在拉取请求上评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审阅评论。
  • 从审阅评论生成 GitHub issue: 通过回复审阅评论,要求 Sourcery 从中创建一个 issue。你也可以回复审阅评论,并加上 @sourcery-ai issue 来创建 issue。
  • 生成拉取请求标题: 在拉取请求标题的任意位置写入 @sourcery-ai,即可随时生成标题。你也可以在拉取请求上评论 @sourcery-ai title 来随时(重新)生成标题。
  • 生成拉取请求摘要: 在拉取请求正文的任意位置写入 @sourcery-ai summary,即可随时在你想要的位置生成 PR 摘要。你也可以在拉取请求上评论 @sourcery-ai summary 来随时(重新)生成摘要。
  • 生成审阅者指南: 在拉取请求上评论 @sourcery-ai guide 来随时(重新)生成审阅者指南。
  • 解决所有 Sourcery 评论: 在拉取请求上评论 @sourcery-ai resolve 来解决所有 Sourcery 评论。如果你已经处理了所有评论,并且不想再看到它们,这会很有用。
  • 驳回所有 Sourcery 审阅: 在拉取请求上评论 @sourcery-ai dismiss 来驳回所有现有的 Sourcery 审阅。如果你想从头开始进行新审阅,这尤其有用——别忘了评论 @sourcery-ai review 来触发新审阅!

自定义你的体验

访问你的 仪表板 以:

  • 启用或禁用审阅功能,例如 Sourcery 生成的拉取请求摘要、审阅者指南等。
  • 更改审阅语言。
  • 添加、删除或编辑自定义审阅说明。
  • 调整其他审阅设置。

获取帮助

Original review guide in English

Reviewer's Guide

This PR refactors all API class methods to static, upgrades Pydantic model definitions for v2 compatibility, centralizes shared models, enriches type annotations and enum usage in data models, and updates project requirements for Python>=3.10 and Pydantic>=2.0.

Entity relationship diagram for new common models and their usage

erDiagram
    DaemonModel ||--o| CpuMemChart : has
    DaemonModel ||--o| ProcessInfo : has
    DaemonModel ||--o| InstanceInfo : has
    OverviewModel ||--o| CpuMemChart : has
    OverviewModel ||--o| InstanceInfo : has
    OverviewModel ||--o| ProcessInfo : has
Loading

Class diagram for refactored API classes with static methods

classDiagram
    class Instance {
        +static search(daemonId, page, page_size, keyword, type, tag)
        +static detail(daemonId, uuid)
        +static create(daemonId, config)
        +static updateConfig(daemonId, uuid, config)
        +static delete(daemonId, uuids, deleteFile)
        +static start(daemonId, uuid)
        +static stop(daemonId, uuid)
        +static restart(daemonId, uuid)
        +static kill(daemonId, uuid)
        +static batchOperation(instances, operation)
        +static update(daemonId, uuid)
        +static command(daemonId, uuid, command)
        +static get_output(daemonId, uuid, size)
        +static reinstall(daemonId, uuid, targetUrl, title, description)
    }
    class File {
        +static show(daemonId, uuid, target, page, page_size, file_name)
        +static content(daemonId, uuid, target)
        +static update(daemonId, uuid, target, text)
        +static download(daemonId, uuid, file_name)
        +static upload(daemonId, uuid, file, upload_dir)
        +static copy(daemonId, uuid, copy_map)
        +static copyOne(daemonId, uuid, source, target)
        +static move(daemonId, uuid, copy_map)
        +static moveOne(daemonId, uuid, source, target)
        +static rename(daemonId, uuid, source, new_name)
        +static zip(daemonId, uuid, source, targets)
        +static unzip(daemonId, uuid, source, target, code)
        +static delete(daemonId, uuid, targets)
        +static createFile(daemonId, uuid, target)
        +static createFloder(daemonId, uuid, target)
    }
    class Daemon {
        +static show()
        +static system()
        +static add(config)
        +static delete(daemonId)
        +static link(daemonId)
        +static update(daemonId, config)
    }
    class Image {
        +static images(daemonId)
        +static containers(daemonId)
        +static network(daemonId)
        +static add(daemonId, dockerFile, name, tag)
        +static progress(daemonId)
    }
    class User {
        +static search(username, page, page_size, role)
        +static create(username, password, permission)
        +static update(uuid, config)
        +static delete(uuids)
    }
    class Overview {
        +static init()
    }
Loading

Class diagram for updated InstanceConfig and related enums

classDiagram
    class InstanceConfig {
        nickname: str
        startCommand: str
        stopCommand: str
        cwd: str
        ie: str
        oe: str
        createDatetime: int
        lastDatetime: int
        type: str
        tag: list[str]
        endTime: int | None
        fileCode: str
        processType: str
        updateCommand: str
        actionCommandlist: list[str]
        crlf: CRLFType
        docker: DockerConfig
        enableRcon: bool
        rconPassword: str
        rconPort: int
        rconIp: str
        terminalOption: TerminalOption
        eventTask: EventTask
        pingConfig: PingConfig
        runAs: str
    }
    class CRLFType {
        LF
        CR
        CRLF
    }
    class Status {
        BUSY
        STOP
        STOPPING
        STARTING
        RUNNING
    }
    InstanceConfig --> CRLFType
    InstanceConfig --> DockerConfig
    InstanceConfig --> TerminalOption
    InstanceConfig --> EventTask
    InstanceConfig --> PingConfig
Loading

Class diagram for new common models module

classDiagram
    class CpuMemChart {
        cpu: float
        mem: float
    }
    class ProcessInfo {
        cpu: int
        memory: int
        cwd: str
    }
    class InstanceInfo {
        running: int
        total: int
    }
Loading

Class diagram for updated FileItem and FileType enum

classDiagram
    class FileItem {
        name: str
        size: int
        time: str
        mode: int
        type: FileType
        daemonId: str
        uuid: str
        target: str
        file_name: str
    }
    class FileType {
        FOLDER
        FILE
    }
    FileItem --> FileType
Loading

Class diagram for updated UserModel and UserPermission enum

classDiagram
    class UserModel {
        uuid: str
        userName: str
        passWord: str
        passWordType: int
        salt: str
        permission: UserPermission
        registerTime: str
        loginTime: str
        apiKey: str
        isInit: bool
        secret: str
        open2FA: bool
        instances: list[UserInstancesList]
    }
    class UserPermission {
        BANNED
        USER
        ADMIN
    }
    UserModel --> UserPermission
Loading

File-Level Changes

Change Details Files
Converted API instance methods to static methods
  • Added @staticmethod decorators to all API methods
  • Replaced Instance().method calls with Instance.method
  • Updated client entry points (Overview.init instead of Overview())
mcsmapi/apis/file.py
mcsmapi/apis/instance.py
mcsmapi/apis/daemon.py
mcsmapi/apis/image.py
mcsmapi/apis/user.py
mcsmapi/apis/overview.py
mcsmapi/__init__.py
Migrated Pydantic models to v2 conventions
  • Replaced BaseModel.dict() with BaseModel.model_dump()
  • Swapped fields.keys() usage with model_fields.keys()
  • Updated dict-based instantiation to use model_dump and model_fields
mcsmapi/models/instance.py
mcsmapi/models/daemon.py
mcsmapi/models/user.py
Extracted and reused common model definitions
  • Created mcsmapi/models/common.py with CpuMemChart, ProcessInfo, InstanceInfo
  • Imported common models in daemon.py and overview.py
  • Removed duplicate model classes from source modules
mcsmapi/models/common.py
mcsmapi/models/daemon.py
mcsmapi/models/overview.py
Enhanced data models with richer typing and enums
  • Replaced typing.List/Optional/Union with Python 3.10 native types and Literal
  • Added IntEnum classes for CRLFType, Status, UserPermission, FileType
  • Enriched DockerConfig, FileItem, and other models with extra fields
mcsmapi/models/instance.py
mcsmapi/models/image.py
mcsmapi/models/file.py
mcsmapi/models/user.py
Updated project configuration for modern Python and Pydantic
  • Set requires-python to ">=3.10"
  • Pinned pydantic to ">=2.0.0"
pyproject.toml

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
Copy Markdown
Contributor

@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.

你好 - 我已经审阅了你的更改,它们看起来很棒!

AI 代理的提示
请处理此代码审查中的评论:
## 个人评论

### 评论 1
<location> `mcsmapi/models/instance.py:87` </location>
<code_context>
+    """进程类型 (如 docker, local)"""
     updateCommand: str = "shutdown -s"
+    """更新命令"""
+    actionCommandlist: list[str] = []
     """实例可执行的操作命令列表"""
-    actionCommandList: List[str] = []
</code_context>

<issue_to_address>
命名不一致:'actionCommandlist' 应为 'actionCommandList' 以保持一致性。

请将 'actionCommandlist' 重命名为 'actionCommandList',以保持一致的驼峰命名并避免潜在的混淆或错误。
</issue_to_address>

### 评论 2
<location> `mcsmapi/models/instance.py` </location>
<code_context>
+    def files(self, target: str = "", page: int = 0, page_size: int = 100) -> FileList:
</code_context>

<issue_to_address>
返回类型注解拼写错误:'Filelist' 应为 'FileList'。

请更新文档字符串以使用正确的类名 'FileList' 以保持一致性。
</issue_to_address>

### 评论 3
<location> `mcsmapi/models/file.py:214` </location>
<code_context>
-        return File().createFile(self.daemonId, self.uuid, target)
+        return File.createFile(self.daemonId, self.uuid, target)

     def createFloder(self, target: str) -> bool:
         """
</code_context>

<issue_to_address>
方法名拼写错误:'createFloder' 应为 'createFolder'。

请将方法重命名为 'createFolder' 以保持一致性。

建议的实现:

```python
    def createFolder(self, target: str) -> bool:
        """
        """
        from mcsmapi.apis.file import File

        return File.createFile(self.daemonId, self.uuid, target)

```

如果你的代码库中其他地方有调用 `createFloder`,你也需要将它们更新为 `createFolder`。
</issue_to_address>

### 评论 4
<location> `mcsmapi/models/instance.py:25` </location>
<code_context>
+    RUNNING = 3
+
+
 class TerminalOption(BaseModel):
     """终端选项"""

</code_context>

<issue_to_address>
考虑用 Pydantic 字段描述替换每个字段的文档字符串,以使模型类更简洁。

考虑将每个字段的文档字符串合并到 Pydantic `Field(..., description=…)` 调用中。这将消除数十行重复的 `"""…"""`,并使类更加简洁,同时保留所有元数据:

```python
from enum import IntEnum
from typing import Optional, List
from pydantic import BaseModel, Field

class CRLFType(IntEnum):
    """换行符"""
    LF = 0
    CR = 1
    CRLF = 2

class Status(IntEnum):
    """实例状态"""
    BUSY = -1
    STOP = 0
    STOPPING = 1
    STARTING = 2
    RUNNING = 3

class InstanceConfig(BaseModel):
    nickname: str = Field("New Name", description="实例名称")
    startCommand: str = Field("cmd.exe", description="启动命令")
    stopCommand: str = Field("^C", description="停止命令")
    cwd: str = Field("", description="工作目录")
    ie: str = Field("utf8", description="输入编码")
    oe: str = Field("utf8", description="输出编码")
    createDatetime: int = Field(0, description="创建时间 (Unix 时间戳)")
    lastDatetime: int = Field(0, description="最后修改时间 (Unix 时间戳)")
    type: str = Field("universal", description="实例类型 (universal, minecraft 等)")
    tag: List[str] = Field(default_factory=list, description="实例标签")
    endTime: Optional[int] = Field(None, description="实例到期时间")
    fileCode: str = Field("utf8", description="文件编码")
    processType: str = Field("docker", description="进程类型 (如 docker, local)")
    updateCommand: str = Field("shutdown -s", description="更新命令")
    actionCommandList: List[str] = Field(default_factory=list, description="实例可执行的操作命令列表")
    crlf: CRLFType = Field(CRLFType.CRLF, description="换行符")
    docker: DockerConfig = Field(default_factory=DockerConfig, description="Docker 相关配置")
    enableRcon: bool = Field(True, description="是否启用 RCON 远程控制")
    rconPassword: str = Field("", description="RCON 连接密码")
    rconPort: int = Field(2557, description="RCON 端口")
    rconIp: str = Field("", description="RCON IP 地址")
    # ...and so on for the rest of your fields
````TerminalOption``EventTask``PingConfig``ProcessInfo` 等中重复相同的模式,并删除独立的三个引号的文档字符串。这将在模式/IDE 提示中保留所有描述,同时大幅减少样板代码。
</issue_to_address>

### 评论 5
<location> `mcsmapi/apis/file.py:8` </location>
<code_context>


 class File:
+    @staticmethod
     def show(
</code_context>

<issue_to_address>
考虑将静态方法类重构为顶级函数,以简化代码并删除不必要的装饰器和参数。

当没有共享状态时,你实际上不需要一个全是 `@staticmethod` 包装方法的类。将它们提取到顶级函数(或少量模块)中,你可以删除数十个装饰器和未使用的 `self` 参数。

例如,创建一个新文件 `mcsmapi/file_api.py````python
# mcsmapi/file_api.py
from mcsmapi.pool    import ApiPool
from mcsmapi.request import send, upload
from mcsmapi.models.file import CommonConfig, FileList
import urllib.parse, os

def show(
    daemonId: str,
    uuid: str,
    target: str = "",
    page: int = 0,
    page_size: int = 100,
    file_name: str = "",
) -> FileList:
    result = send(
        "PUT",
        f"{ApiPool.FILE}/list",
        params={"daemonId": daemonId, "uuid": uuid},
        data={
            "target": target,
            "page": page,
            "page_size": page_size,
            "file_name": file_name,
        },
    )
    return FileList(**result, daemonId=daemonId, uuid=uuid)

def content(daemonId: str, uuid: str, target: str) -> str | bytes:
    return send(
        "PUT",
        f"{ApiPool.FILE}",
        params={"daemonId": daemonId, "uuid": uuid},
        data={"target": target},
    )

async def upload(daemonId: str, uuid: str, file: bytes, upload_dir: str) -> bool:
    result = send(
        "POST",
        f"{ApiPool.FILE}/upload",
        params={"daemonId": daemonId, "uuid": uuid, "upload_dir": upload_dir},
    )
    cfg      = CommonConfig(**result)
    proto    = Request.mcsm_url.split("://")[0]
    base_url = urllib.parse.urljoin(f"{proto}://{cfg.addr}", "upload")
    final    = urllib.parse.urljoin(base_url, cfg.password)
    await upload(final, file)
    return True

# …etc for update, download, copy, move, delete, etc…
```

然后在你的公共 API 中,你只需:

```python
from .file_api import (
    show, content, update, download, upload,
    copy, move, copyOne, moveOne,
    rename, zip, unzip, delete, createFile, createFolder
)
```

这将删除所有 `@staticmethod` 行,消除方法中从未使用过的 `self`,并使调用站点同样容易(例如 `file_api.show(...)`)。
</issue_to_address>

### 评论 6
<location> `mcsmapi/apis/instance.py:12` </location>
<code_context>


 class Instance:
+    @staticmethod
     def search(
</code_context>

<issue_to_address>
考虑将静态方法类重构为模块级函数,并使用共享助手来减少重复和样板代码。

以下是将几乎相同的静态方法折叠成普通的模块级函数 + 一个小型助手,并完全删除类的一种方法:

1. 在文件顶部引入一个助手:

```python
def _instance_call(
    method: str,
    endpoint: str,
    params: dict[str, Any] | None = None,
    data: Any | None = None,
) -> Any:
    return send(method, endpoint, params=params, data=data)
```

2. 将你的静态方法转换为最小函数:

```python
def detail(daemonId: str, uuid: str) -> InstanceDetail:
    res = _instance_call("GET", ApiPool.INSTANCE, params={"daemonId": daemonId, "uuid": uuid})
    return InstanceDetail(**res)

def create(daemonId: str, config: dict[str, Any]) -> InstanceCreateResult:
    res = _instance_call("POST", ApiPool.INSTANCE, params={"daemonId": daemonId}, data=InstanceConfig(**config).dict())
    return InstanceCreateResult(**res)
```

3. 将所有“start/stop/restart/kill/command/output”折叠成一个单一的工厂:

```python
def _power_action(
    action: Literal["open","stop","restart","kill","command","outputlog"],
    daemonId: str,
    uuid: str,
    **extra,
) -> Any:
    path = f"{ApiPool.PROTECTED_INSTANCE}/{action}"
    params = {"daemonId": daemonId, "uuid": uuid, **extra}
    res = _instance_call("GET", path, params=params)
    # most of these return instanceUuid; outputlog returns raw string
    return extra.get("command") and res.get("instanceUuid", True) or res
```

使用示例:

```python
def start(daemonId: str, uuid: str) -> str | bool:
    return _power_action("open", daemonId, uuid)

def command(daemonId: str, uuid: str, command: str) -> str | bool:
    return _power_action("command", daemonId, uuid, command=command)

def get_output(daemonId: str, uuid: str, size: int | str = "") -> str:
    return _power_action("outputlog", daemonId, uuid, size=size)
```

这将删除所有 `@staticmethod` 噪音,合并重复的发送调用,并保持完整的功能。
</issue_to_address>

Sourcery 对开源免费 - 如果您喜欢我们的评论,请考虑分享它们 ✨
帮助我更有用!请点击每个评论上的 👍 或 👎,我将使用反馈来改进您的评论。
Original comment in English

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `mcsmapi/models/instance.py:87` </location>
<code_context>
+    """进程类型 (如 docker, local)"""
     updateCommand: str = "shutdown -s"
+    """更新命令"""
+    actionCommandlist: list[str] = []
     """实例可执行的操作命令列表"""
-    actionCommandList: List[str] = []
</code_context>

<issue_to_address>
Inconsistent naming: 'actionCommandlist' should be 'actionCommandList' for consistency.

Please rename 'actionCommandlist' to 'actionCommandList' to maintain consistent camelCase naming and avoid potential confusion or bugs.
</issue_to_address>

### Comment 2
<location> `mcsmapi/models/instance.py` </location>
<code_context>
+    def files(self, target: str = "", page: int = 0, page_size: int = 100) -> FileList:
</code_context>

<issue_to_address>
Return type annotation typo: 'Filelist' should be 'FileList'.

Please update the docstring to use the correct class name 'FileList' for consistency.
</issue_to_address>

### Comment 3
<location> `mcsmapi/models/file.py:214` </location>
<code_context>
-        return File().createFile(self.daemonId, self.uuid, target)
+        return File.createFile(self.daemonId, self.uuid, target)

     def createFloder(self, target: str) -> bool:
         """
</code_context>

<issue_to_address>
Typo in method name: 'createFloder' should be 'createFolder'.

Please rename the method to 'createFolder' for consistency.

Suggested implementation:

```python
    def createFolder(self, target: str) -> bool:
        """
        """
        from mcsmapi.apis.file import File

        return File.createFile(self.daemonId, self.uuid, target)

```

If there are any calls to `createFloder` elsewhere in your codebase, you will need to update those to `createFolder` as well.
</issue_to_address>

### Comment 4
<location> `mcsmapi/models/instance.py:25` </location>
<code_context>
+    RUNNING = 3
+
+
 class TerminalOption(BaseModel):
     """终端选项"""

</code_context>

<issue_to_address>
Consider replacing per-field docstrings with Pydantic Field descriptions to make model classes more concise.

Consider collapsing per‐field docstrings into Pydantic `Field(..., description=…)` calls. This will remove dozens of lines of repeated `"""…"""` and make the class far more concise while keeping all metadata:

```python
from enum import IntEnum
from typing import Optional, List
from pydantic import BaseModel, Field

class CRLFType(IntEnum):
    """换行符"""
    LF = 0
    CR = 1
    CRLF = 2

class Status(IntEnum):
    """实例状态"""
    BUSY = -1
    STOP = 0
    STOPPING = 1
    STARTING = 2
    RUNNING = 3

class InstanceConfig(BaseModel):
    nickname: str = Field("New Name", description="实例名称")
    startCommand: str = Field("cmd.exe", description="启动命令")
    stopCommand: str = Field("^C", description="停止命令")
    cwd: str = Field("", description="工作目录")
    ie: str = Field("utf8", description="输入编码")
    oe: str = Field("utf8", description="输出编码")
    createDatetime: int = Field(0, description="创建时间 (Unix 时间戳)")
    lastDatetime: int = Field(0, description="最后修改时间 (Unix 时间戳)")
    type: str = Field("universal", description="实例类型 (universal, minecraft 等)")
    tag: List[str] = Field(default_factory=list, description="实例标签")
    endTime: Optional[int] = Field(None, description="实例到期时间")
    fileCode: str = Field("utf8", description="文件编码")
    processType: str = Field("docker", description="进程类型 (如 docker, local)")
    updateCommand: str = Field("shutdown -s", description="更新命令")
    actionCommandList: List[str] = Field(default_factory=list, description="实例可执行的操作命令列表")
    crlf: CRLFType = Field(CRLFType.CRLF, description="换行符")
    docker: DockerConfig = Field(default_factory=DockerConfig, description="Docker 相关配置")
    enableRcon: bool = Field(True, description="是否启用 RCON 远程控制")
    rconPassword: str = Field("", description="RCON 连接密码")
    rconPort: int = Field(2557, description="RCON 端口")
    rconIp: str = Field("", description="RCON IP 地址")
    # ...and so on for the rest of your fields
```

Repeat the same pattern in `TerminalOption`, `EventTask`, `PingConfig`, `ProcessInfo`, etc., and remove the standalone triple‐quoted docstrings. This keeps all descriptions intact in schema/IDE hints but slashes the boilerplate.
</issue_to_address>

### Comment 5
<location> `mcsmapi/apis/file.py:8` </location>
<code_context>


 class File:
+    @staticmethod
     def show(
</code_context>

<issue_to_address>
Consider refactoring the class of static methods into top-level functions to simplify the code and remove unnecessary decorators and parameters.

You don’t actually need a class full of `@staticmethod`-wrapped methods when there is no shared state.  Pull them out into top‐level functions (or a small handful of modules) and you can delete dozens of decorators and the unused `self` parameter.  

For example, create a new file `mcsmapi/file_api.py`:

```python
# mcsmapi/file_api.py
from mcsmapi.pool    import ApiPool
from mcsmapi.request import send, upload
from mcsmapi.models.file import CommonConfig, FileList
import urllib.parse, os

def show(
    daemonId: str,
    uuid: str,
    target: str = "",
    page: int = 0,
    page_size: int = 100,
    file_name: str = "",
) -> FileList:
    result = send(
        "PUT",
        f"{ApiPool.FILE}/list",
        params={"daemonId": daemonId, "uuid": uuid},
        data={
            "target": target,
            "page": page,
            "page_size": page_size,
            "file_name": file_name,
        },
    )
    return FileList(**result, daemonId=daemonId, uuid=uuid)

def content(daemonId: str, uuid: str, target: str) -> str | bytes:
    return send(
        "PUT",
        f"{ApiPool.FILE}",
        params={"daemonId": daemonId, "uuid": uuid},
        data={"target": target},
    )

async def upload(daemonId: str, uuid: str, file: bytes, upload_dir: str) -> bool:
    result = send(
        "POST",
        f"{ApiPool.FILE}/upload",
        params={"daemonId": daemonId, "uuid": uuid, "upload_dir": upload_dir},
    )
    cfg      = CommonConfig(**result)
    proto    = Request.mcsm_url.split("://")[0]
    base_url = urllib.parse.urljoin(f"{proto}://{cfg.addr}", "upload")
    final    = urllib.parse.urljoin(base_url, cfg.password)
    await upload(final, file)
    return True

# …etc for update, download, copy, move, delete, etc…
```

Then in your public API you simply:

```python
from .file_api import (
    show, content, update, download, upload,
    copy, move, copyOne, moveOne,
    rename, zip, unzip, delete, createFile, createFolder
)
```

This removes every `@staticmethod` line, gets rid of `self` on methods that never use it, and makes call‐sites just as easy (e.g. `file_api.show(...)`).
</issue_to_address>

### Comment 6
<location> `mcsmapi/apis/instance.py:12` </location>
<code_context>


 class Instance:
+    @staticmethod
     def search(
</code_context>

<issue_to_address>
Consider refactoring the class of static methods into module-level functions with shared helpers to reduce duplication and boilerplate.

Here’s one way to collapse almost‐identical static methods into plain module-level functions + a small helper, dropping the class entirely:

1. Introduce a helper at top of the file:

```python
def _instance_call(
    method: str,
    endpoint: str,
    params: dict[str, Any] | None = None,
    data: Any | None = None,
) -> Any:
    return send(method, endpoint, params=params, data=data)
```

2. Turn your static methods into minimal functions:

```python
def detail(daemonId: str, uuid: str) -> InstanceDetail:
    res = _instance_call("GET", ApiPool.INSTANCE, params={"daemonId": daemonId, "uuid": uuid})
    return InstanceDetail(**res)

def create(daemonId: str, config: dict[str, Any]) -> InstanceCreateResult:
    res = _instance_call("POST", ApiPool.INSTANCE, params={"daemonId": daemonId}, data=InstanceConfig(**config).dict())
    return InstanceCreateResult(**res)
```

3. Collapse all “start/stop/restart/kill/command/output” into a single factory:

```python
def _power_action(
    action: Literal["open","stop","restart","kill","command","outputlog"],
    daemonId: str,
    uuid: str,
    **extra,
) -> Any:
    path = f"{ApiPool.PROTECTED_INSTANCE}/{action}"
    params = {"daemonId": daemonId, "uuid": uuid, **extra}
    res = _instance_call("GET", path, params=params)
    # most of these return instanceUuid; outputlog returns raw string
    return extra.get("command") and res.get("instanceUuid", True) or res
```

Usage examples:

```python
def start(daemonId: str, uuid: str) -> str | bool:
    return _power_action("open", daemonId, uuid)

def command(daemonId: str, uuid: str, command: str) -> str | bool:
    return _power_action("command", daemonId, uuid, command=command)

def get_output(daemonId: str, uuid: str, size: int | str = "") -> str:
    return _power_action("outputlog", daemonId, uuid, size=size)
```

This removes all the `@staticmethod` noise, collapses duplicated send-calls, and keeps full functionality.
</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.

@@ -10,8 +10,8 @@


class Instance:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (complexity): 考虑将静态方法类重构为模块级函数,并使用共享助手来减少重复和样板代码。

以下是将几乎相同的静态方法折叠成普通的模块级函数 + 一个小型助手,并完全删除类的一种方法:

  1. 在文件顶部引入一个助手:
def _instance_call(
    method: str,
    endpoint: str,
    params: dict[str, Any] | None = None,
    data: Any | None = None,
) -> Any:
    return send(method, endpoint, params=params, data=data)
  1. 将你的静态方法转换为最小函数:
def detail(daemonId: str, uuid: str) -> InstanceDetail:
    res = _instance_call("GET", ApiPool.INSTANCE, params={"daemonId": daemonId, "uuid": uuid})
    return InstanceDetail(**res)

def create(daemonId: str, config: dict[str, Any]) -> InstanceCreateResult:
    res = _instance_call("POST", ApiPool.INSTANCE, params={"daemonId": daemonId}, data=InstanceConfig(**config).dict())
    return InstanceCreateResult(**res)
  1. 将所有“start/stop/restart/kill/command/output”折叠成一个单一的工厂:
def _power_action(
    action: Literal["open","stop","restart","kill","command","outputlog"],
    daemonId: str,
    uuid: str,
    **extra,
) -> Any:
    path = f"{ApiPool.PROTECTED_INSTANCE}/{action}"
    params = {"daemonId": daemonId, "uuid": uuid, **extra}
    res = _instance_call("GET", path, params=params)
    # most of these return instanceUuid; outputlog returns raw string
    return extra.get("command") and res.get("instanceUuid", True) or res

使用示例:

def start(daemonId: str, uuid: str) -> str | bool:
    return _power_action("open", daemonId, uuid)

def command(daemonId: str, uuid: str, command: str) -> str | bool:
    return _power_action("command", daemonId, uuid, command=command)

def get_output(daemonId: str, uuid: str, size: int | str = "") -> str:
    return _power_action("outputlog", daemonId, uuid, size=size)

这将删除所有 @staticmethod 噪音,合并重复的发送调用,并保持完整的功能。

Original comment in English

issue (complexity): Consider refactoring the class of static methods into module-level functions with shared helpers to reduce duplication and boilerplate.

Here’s one way to collapse almost‐identical static methods into plain module-level functions + a small helper, dropping the class entirely:

  1. Introduce a helper at top of the file:
def _instance_call(
    method: str,
    endpoint: str,
    params: dict[str, Any] | None = None,
    data: Any | None = None,
) -> Any:
    return send(method, endpoint, params=params, data=data)
  1. Turn your static methods into minimal functions:
def detail(daemonId: str, uuid: str) -> InstanceDetail:
    res = _instance_call("GET", ApiPool.INSTANCE, params={"daemonId": daemonId, "uuid": uuid})
    return InstanceDetail(**res)

def create(daemonId: str, config: dict[str, Any]) -> InstanceCreateResult:
    res = _instance_call("POST", ApiPool.INSTANCE, params={"daemonId": daemonId}, data=InstanceConfig(**config).dict())
    return InstanceCreateResult(**res)
  1. Collapse all “start/stop/restart/kill/command/output” into a single factory:
def _power_action(
    action: Literal["open","stop","restart","kill","command","outputlog"],
    daemonId: str,
    uuid: str,
    **extra,
) -> Any:
    path = f"{ApiPool.PROTECTED_INSTANCE}/{action}"
    params = {"daemonId": daemonId, "uuid": uuid, **extra}
    res = _instance_call("GET", path, params=params)
    # most of these return instanceUuid; outputlog returns raw string
    return extra.get("command") and res.get("instanceUuid", True) or res

Usage examples:

def start(daemonId: str, uuid: str) -> str | bool:
    return _power_action("open", daemonId, uuid)

def command(daemonId: str, uuid: str, command: str) -> str | bool:
    return _power_action("command", daemonId, uuid, command=command)

def get_output(daemonId: str, uuid: str, size: int | str = "") -> str:
    return _power_action("outputlog", daemonId, uuid, size=size)

This removes all the @staticmethod noise, collapses duplicated send-calls, and keeps full functionality.

@molanp molanp merged commit c345fc8 into main Aug 15, 2025
1 check passed
molanp added a commit that referenced this pull request Jan 31, 2026
- 将 API 类中的实例方法改为静态方法,简化使用
- 优化模型定义,提高代码可读性和维护性
- 新增 common 模型模块,用于定义通用的模型结构
- 调整文件列表和 Docker 相关模型结构,增强数据表达能力
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.

1 participant