S3 设置统一弹窗与内核重启空实现

December 14, 2025
3 min read
By devshan

Table of Contents

This is a list of all the sections in this post. Click on any of them to jump to that section.

背景

  • 早期的 S3 配置是零散的:
    • 端点、AccessKey、SecretKey、Bucket 可能通过多个入口修改。
    • 没有“确认后一次性生效”的概念。
  • 实际上,S3 是 Go 核心的依赖,Flutter 只是前端配置界面:
    • 改 S3 配置本质上是“改核心进程的启动参数/环境”。
    • 从使用心智上,更符合“改完之后重启核心服务”的模型。
  • 同时,后续还计划用 gomobile 把核心跑在同一进程内,需要预留“重启核心”的能力。

本次调整的目标:

  • 把 S3 相关设置收敛到一个弹窗中,一次填完再确认。
  • 预置一个 _restartCore 空实现,将来对接 gomobile 时直接填充。

实现总览

  • 主要改动集中在设置页:
    • 统一入口:client/lib/ui/settings_page.dart:544-581
    • 弹窗逻辑:_showS3ConfigDialogclient/lib/ui/settings_page.dart:169-301
    • 预留的重启方法:_restartCoreclient/lib/ui/settings_page.dart:169
  • 状态与持久化由 AppState 提供:
    • S3 偏好加载:_loadPreferencesclient/lib/core/state/app_state.dart:133-151
    • S3 相关 setter:setS3Endpoint / setS3AccessKey / setS3SecretKey / setS3Bucket / setS3UseSslclient/lib/core/state/app_state.dart:286-337

统一 S3 配置弹窗设计

入口展示

  • 在设置页的“存储”区域新增“S3 配置”入口:
    • 左侧图标使用 MdiIcons.cloud
    • 副标题根据当前配置智能展示:
      • 若端点和桶均为空:显示“使用默认配置”。
      • 若只有桶:显示“默认端点 · 桶:{bucket}”。
      • 若只有端点:显示“{endpoint}”。
      • 若两者都有:显示“{endpoint} · 桶:{bucket}”。
    • 代码位置:client/lib/ui/settings_page.dart:544-581

弹窗内容

  • 调用入口:点击 ListTile 后执行 _showS3ConfigDialog
  • 弹窗内部字段:
    • S3 端点
      • 文本框,默认填入 appState.s3Endpoint ?? ''
      • 提示:例如:http://127.0.0.1:9000,留空使用默认
    • AccessKey
      • 文本框,默认填入 appState.s3AccessKey ?? ''
      • 提示:访问密钥,留空表示不设置
    • SecretKey
      • 文本框,obscureText: true
      • 默认填入 appState.s3SecretKey ?? ''
      • 提示:访问密钥,留空表示不设置
    • 存储桶
      • 文本框,默认填入 appState.s3Bucket ?? ''
      • 提示:例如:e2e-pan,留空表示使用默认
    • 使用 HTTPS 开关:
      • 绑定 useSsl,初始值为 appState.s3UseSsl
      • 提示文案:默认关闭,以提升传输速度
  • 弹窗的确认逻辑:
    • 取消Navigator.pop(ctx, false),不保存。
    • 确认Navigator.pop(ctx, true),继续后续保存流程。
    • 位置:client/lib/ui/settings_page.dart:169-243

保存行为

  • 弹窗关闭后,如果选择确认:
    • 分别从四个 TextEditingControlleruseSsl 中读取最终值。
    • 将空字符串视为“恢复默认/不设置”:
      • endpoint 为空:setS3Endpoint(null)
      • accessKey 为空:setS3AccessKey(null)
      • secretKey 为空:setS3SecretKey(null)
      • bucket 为空:setS3Bucket(null)
    • 非空时按原样保存。
  • TLS 选项:
    • 直接通过 setS3UseSsl(useSsl) 写入偏好。
  • 所有 setter 统一更新 SharedPreferencesnotifyListeners
    • 参考:client/lib/core/state/app_state.dart:286-339
  • 保存结束后:
    • 调用 _restartCore()
    • 弹出 SnackBar:“已更新 S3 配置”。

_restartCore 空实现的意义

当前行为

  • 方法定义:client/lib/ui/settings_page.dart:169
    • 签名:Future<void> _restartCore() async {}
    • 目前不做任何事,只是一个占位。
  • 原因:
    • 当前架构下,Go 核心是一个独立进程,通过 HTTP 在本地/局域网访问。
    • Flutter 客户端实际上无法直接“重启核心”,只能提示手动重启。
    • 提前在 UI 里把“改配置之后要重启核心”的意图明确下来。

未来对接思路

  • 当后续切换到 gomobile / FFI 方案时,这个函数将成为对接点:
    • 可能的行为:
      • 优雅停止当前核心实例(关闭所有连接、flush 持久化状态)。
      • 携带新的配置重新初始化核心。
      • 重新触发健康检查和 bootstrap 流程。
  • 相比于到处散落的“改配置后自己想办法”的代码,一个统一的 _restartCore
    • 有利于集中处理错误和状态迁移。
    • 可以在这里统一处理“重启后 token、元数据缓存、传输队列”等衔接逻辑。

收获

  • 交互层面:
    • S3 设置从“分散、多入口”收敛成一个弹窗,认知开销更低。
    • 一次填完、一次确认,避免某个字段忘记点“保存”的情况。
  • 工程层面:
    • AppState 封装所有 S3 偏好,UI 只关心展示与收集。
    • 通过 setS3* 系列方法保证:
      • 内存状态更新。
      • SharedPreferences 中的持久化同步。
      • 下游依赖者收到变更通知。
  • 架构演进层面:
    • _restartCore 提前站好坑,未来接 gomobile 时不会反过来找 UI 里的“重启核心”逻辑。
    • 当前阶段保持空实现,不增加多余复杂度。