返回项目列表
Portman 标志

Portman

VSCode 插件,可在任何操作系统上通过图形界面管理网络端口。

+2k 下载VSCodeMarketplace

在软件开发过程中,一个经常出现的业务障碍是网络端口分配冲突(在 Node.js 环境中被称为 EADDRINUSE 错误)。当先前的进程(无论是意图运行的还是孤儿/僵尸进程)在特定网络接口和端口上保持打开监听 socket 时,就会发生这种情况,从而阻止新实例绑定到该资源。

手动解决此状态需要开发者通过命令行界面 (CLI) 直接与操作系统交互,以:

  1. 探测: 运行网络分析工具(例如 lsof, netstat, ss)。
  2. 过滤: 处理标准输出 (stdout) 以隔离绑定到冲突端口的进程。
  3. 识别: 提取进程标识符 (PID)。
  4. 终止: 向识别出的 PID 发送系统信号(如 SIGKILL)。

业务解决方案

Portman 将此诊断和干预工作流自动化并抽象化,直接将其集成到集成开发环境 (IDE) 中。

功能工作流总结为:

  1. 系统状态提取: 扩展以透明的方式与宿主操作系统的原生 API 和二进制文件交互,以检索网络连接的当前状态。
  2. 转换与映射: 从操作系统提取的原始信息被规范化为结构化的领域模型。
  3. 实时展示: 规范化的模型在 VS Code 图形界面内部渲染为交互式树状结构。
  4. 执行动作: 通过内置命令,该工具允许用户选择树节点,并以统一的方式将终止信号发送到底层进程,而无需考虑所使用的操作系统。

技术分析:架构与模型

为确保软件生命周期支持可持续增长、隔离的可测试性以及跨多个操作系统(Linux, macOS, Windows)的横向适应性,我在 干净架构 (Clean Architecture) 和 领域驱动设计 (Domain-Driven Design - DDD) 原则下设计了项目结构。

代码在概念上分为四个同心层,其中依赖关系严格向内流动(指向领域中心)。

graph TD
    subgraph ext["外部层 (基础设施与呈现)"]
        VS[VS Code Extension API]
        CLI[OS Binaries: netstat, lsof, ss]
    end

    subgraph pres["呈现层"]
        PTD[ProcessTreeDataProvider]
        Cmds[KillProcessCommand]
    end

    subgraph app["应用层"]
        SP[UseCase: SearchProcesses]
        KP[UseCase: KillProcess]
    end

    subgraph dom["领域层"]
        Model[Aggregate Root: Process]
        RepoInt[Interface: ProcessRepository]
    end

    VS --> PTD
    VS --> Cmds
    PTD --> SP
    Cmds --> KP
    SP --> RepoInt
    KP --> RepoInt
    CLI -.->|实现| RepoInt

    classDef domain fill:#14b8a6,fill-opacity:0.3,stroke:#0d9488,stroke-width:2px;
    classDef app fill:#14b8a6,fill-opacity:0.12,stroke:#0d9488,stroke-width:2px;
    classDef pres fill:#737373,fill-opacity:0.14,stroke:#737373,stroke-width:2px;
    classDef external fill:#737373,fill-opacity:0.06,stroke:#737373,stroke-width:1px,stroke-dasharray:4 4;

    class Model,RepoInt domain;
    class SP,KP app;
    class PTD,Cmds pres;
    class VS,CLI external;

1. 领域核心 (Domain)

领域模型与任何外部依赖、框架或操作系统细节隔离。其主要目标是建模网络进程的抽象。

聚合 Process

核心实体是 Process,它充当 Aggregate Root。它由多个值对象 (Value Objects) 组成,这些值对象在实例化时保证数据的完整性:

  • ProcessId:唯一标识符 (PID)。
  • ProcessProgram:可执行文件或守护进程的名称。
  • Protocol:传输协议 (TCP, UDP)。
  • Address:由 AddressHost(本地/远程 IP 或主机名)和 AddressPort(数字端口)组成。
  • ProcessStatus:连接的当前状态(例如 LISTEN, ESTABLISHED)。
classDiagram
    class Process {
        +ProcessId id
        +ProcessProgram program
        +Protocol protocol
        +Address local
        +Address remote
        +ProcessStatus status
        +String icon
        +String label
        +String description
        +String tooltip
    }

    class Address {
        +AddressHost host
        +AddressPort port
    }

    class ProcessRepository {
        <<Interface>>
        +search() Promise~Process[]~
        +kill(process: Process) Promise~void~
    }

    Process "1" *-- "2" Address : local/remote
    ProcessRepository --> Process : 管理

此外,领域定义了契约 ProcessRepository,该契约建立了系统所需的基础搜索和终止操作,而无需规定 如何 实现它们。

2. 应用层 (Application)

应用层利用领域的契约编排业务规则。它是围绕特定的用例 (Use Cases) 构建的:

  • SearchProcesses:向仓库发出查询 (Query),以检索 Process 对象数组。
  • KillProcess:向仓库发出命令 (Command),以删除特定的 Process 对象。

这些用例是无状态的,并且依赖于运行时注入的具体仓库。

3. 基础设施层 (Infrastructure)

这里存在 ProcessRepository 接口的技术实现。依赖注入在应用的入口点 (extension.ts) 进行管理,评估环境变量 process.platform 以实例化正确的适配器。

  • LinuxProcessRepository:优先通过 netstat 进行提取。如果前者不存在,它拥有向二进制文件 ss 的平滑降级机制 (graceful fallback)。此外,它评估配置 portman.linux.asRootUser,以便在需要时通过 pkexec 或 sudo 提升权限。
  • MacProcessRepository:以原生方式与 lsof -i -P -n 交互。
  • WindowsProcessRepository:调用基于 PowerShell 的实现 (Get-NetTCPConnection) 或继承的 MS-DOS 命令 (netstat -a -b -n -o)。

每个仓库都将标准输出的语法分析委托给特定的转换器类(例如 MacNetstatProcessTransformer),这些类解析原始文本字符串,验证结构并把数据映射到领域对象 Process。

4. 呈现层 (Presentation)

该层将业务逻辑与 Visual Studio Code 的扩展 API 隔离开来。 主要组件是 ProcessTreeDataProvider,它实现了 VS Code 的 TreeDataProvider 接口。其职责是订阅 IDE 事件,消费 SearchProcesses 用例,并将 Process 实体数组转换为 ProcessTreeItem(或 ProcessQuickPickItem)实例,以便在用户界面中最终渲染视觉树。它还通过集成在编辑器中的对话框管理操作错误的捕获与展示。


技术栈

为本项目选择的工具链反映了构建优化打包、强类型且与 Node.js (Electron) 运行环境紧密绑定的产物的需求。

技术 / 工具在架构中的角色功能目的
TypeScript (v5.x)主要开发语言提供静态分析和强类型,这对于对领域层实体建模和确保层间契约至关重要。
VS Code Extension API运行环境提供程序化接口 (vscode.*) 用于原生 UI 的渲染、命令注册和侧边栏访问。
Webpack (v5.x)打包工具 / Bundler组合、转译并压缩源码为优化的 extension.js 文件,减少插件的激活延迟。

总结

在 IDE 扩展(一种特征上与视图高度耦合的环境)项目中严格采用干净架构,实现了职责的严格分离。解决网络依赖关系的逻辑核心完全忽略了底层操作系统和 VS Code 的呈现框架。这种抽象确保了原生集成可以被修改、优化或替换(例如,从 CLI 命令过渡到 C++ 内核调用),而不会对端口终止工作流的业务规则或呈现逻辑产生副作用。

拖动可移动图示。按 + 和 − 缩放,方向键移动,0 重置视图。

一起合作

软件工程师、高级全栈开发工程师,常驻玻利维亚Santa Cruz,远程办公。欢迎新的工作机会。