agentsclimarketplace

Dart oss fresh

Skill Python51888/StudyDart-Skills/skills/dart-open-source-projects/dart-oss-fresh

Agent skills for Study Dart

Install
npx -y skills add Python51888/StudyDart-Skills --skill dart-oss-fresh

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

学习 felangel/fresh 开源项目,通过 OAuth Token 自动刷新库理解 Dart 异步编程模式(Future、拦截器、Stream、网络请求链),掌握实际异步架构设计。

SKILL.md

6.0 KB, as published. Nobody here has run it

学习 Fresh Token 自动刷新库项目

Contents

项目概览

项目名称: fresh 作者: felangel (bloc 作者) GitHub: https://github.com/felangel/fresh Stars: 421 | 难度: 中等

一个纯 Dart 的 OAuth Token 自动刷新库。支持 dio、http 和 graphql 三种 HTTP 客户端。核心设计模式是拦截器——在请求发送前自动检查 Token 是否过期,若过期则自动刷新后再发送原请求。项目中 Future 链式处理、Stream 监听、异步错误恢复等技术是学习 dart-async-concurrency 的绝佳案例。

与 dart-async-concurrency 的关联

该项目集中展示了 dart-async-concurrency 技能的核心内容:

dart-async-concurrency 主题项目中的应用
Future 链式处理then / catchError / whenComplete
async/awaitToken 刷新方法
Stream 控制Token 变化通知流
异步错误处理401 拦截 → 刷新 → 重试
Future.wait批量并发请求 Token 刷新等待
异步状态管理刷新锁防止重复刷新

项目架构分析

核心模型

TokenStorage<T> (abstract)
    ├── read()   → Future<T>
    ├── write(T) → Future<void>
    ├── delete() → Future<void>

TokenRefresher<T> (typedef)
    └── Future<T> Function(T? token)

Fresh<T> (class)
    ├── token → Stream<T?>
    ├── authenticationStatus → Stream<AuthenticationStatus>
    ├── setToken(T)
    ├── refreshToken(T?)
    └── close()

拦截器机制

class Fresh<T> {
  final TokenStorage<T> _tokenStorage;
  final TokenRefresher<T> _refreshToken;
  final StreamController<T?> _tokenController;

  final Stream<T?> get token => _tokenController.stream;

  Future<T> _getOrRefreshToken() async {
    final current = await _tokenStorage.read();
    if (current == null || _isExpired(current)) {
      return _refreshToken(current);
    }
    return current;
  }
}

异步编程模式详解

Token 刷新锁模式

防止多个并发请求同时触发刷新:

Future<T?> _refreshLock;
bool _refreshing = false;

Future<T> _validateAndRefresh(T token) async {
  if (_isFresh(token)) return token;

  if (_refreshing) {
    return _refreshLock!; // 等待正在进行的刷新
  }

  _refreshing = true;
  _refreshLock = _refreshToken(token)
      .then((newToken) {
        _refreshing = false;
        return newToken;
      })
      .catchError((error) {
        _refreshing = false;
        throw error;
      });

  return _refreshLock!;
}

Stream 广播模式

enum AuthenticationStatus { authenticated, unauthenticated }

final _authController = StreamController<AuthenticationStatus>.broadcast();

Stream<AuthenticationStatus> get authenticationStatus =>
    _authController.stream;

setToken(T token) {
  _authController.add(AuthenticationStatus.authenticated);
}

signOut() async {
  await _tokenStorage.delete();
  _authController.add(AuthenticationStatus.unauthenticated);
}

Workflow: 通过 Fresh 学习 Dart 异步编程

Task Progress

  • Step 1: 阅读 Fresh 接口定义。 从抽象类 TokenStoragetypedef TokenRefresher 理解架构意图。
  • Step 2: 分析拦截器流程。 跟踪一次请求从发出到收到完整响应的 Future 链路。
  • Step 3: 理解 Stream 使用。 标注 token Stream 和 authenticationStatus Stream 的生产和消费逻辑。
  • Step 4: 运行测试。 dart test 观察各个异步场景的测试用例。
  • Step 5: 实现自定义 TokenStorage。 基于 dart:io 文件系统创建持久化的 TokenStorage。
  • Step 6: 编写异步单元测试。 使用 expectLater / emitsInOrder 验证 Stream 行为。
  • Step 7: 添加超时处理。 为 Token 刷新添加超时和重试逻辑。
  • Step 8: Feedback Loop。 运行测试 → 分析异步错误栈 → 修正 → 重复。

条件逻辑

  • 如果对 Future 链不理解: 使用 dart-async-concurrency 技能中 Future 章节逐一对照。
  • 如果需要处理并发刷新: 参考项目的刷新锁模式,避免构造竞态条件。
  • 如果 Stream 消费逻辑不对: 检查是单订阅流还是广播流,确保使用正确的 StreamController 类型。
  • 如果异步错误被吞没: 在 Future 链中添加 .catchError 或使用 try/catch 包裹 await 调用。

Examples

从项目中学到的拦截器模式

Future<Response> _intercept(RequestOptions options) async {
  final token = await _getOrRefreshToken();
  options.headers['Authorization'] = 'Bearer $token';
  return _client.get(options.uri.toString(), headers: options.headers);
}

结合 dart-async-concurrency 的延伸练习:超时重试

Future<T> _refreshWithRetry(T? token, {int retries = 3}) async {
  for (var i = 0; i < retries; i++) {
    try {
      return await _refreshToken(token).timeout(
        const Duration(seconds: 10),
      );
    } on TimeoutException {
      if (i == retries - 1) rethrow;
      await Future.delayed(Duration(seconds: 1 << i)); // 指数退避
    }
  }
  throw Exception('Token 刷新失败,已达最大重试次数');
}

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.