Config抽象类
/// Config file for the CacheManager.
/// [cacheKey] is used for the folder to store files and for the database
/// file name.
/// [stalePeriod] is the time duration in which a cache object is
/// considered 'stale'. When a file is cached but not being used for a
/// certain time the file will be deleted.
/// [maxNrOfCacheObjects] defines how large the cache is allowed to be. If
/// there are more files the files that haven't been used for the longest
/// time will be removed.
/// [repo] is the [CacheInfoRepository] which stores the cache metadata. On
/// Android, iOS and macOS this defaults to [CacheObjectProvider], a
/// sqflite implementation due to legacy. On web this defaults to
/// [NonStoringObjectProvider]. On the other platforms this defaults to
/// [JsonCacheInfoRepository].
/// The [fileSystem] defines where the cached files are stored and the
/// [fileService] defines where files are fetched, for example online.
factory Config(
String cacheKey, {
Duration stalePeriod,
int maxNrOfCacheObjects,
CacheInfoRepository repo,
FileSystem fileSystem,
FileService fileService,
}) = impl.Config;
String get cacheKey;
Duration get stalePeriod;
int get maxNrOfCacheObjects;
CacheInfoRepository get repo;
FileSystem get fileSystem;
FileService get fileService;
Config是一个抽象类,用于定义CacheManager的配置。以下是Config的一些属性和构造函数参数的简要解释:
cacheKey: 用于存储文件和数据库文件名的文件夹的名称。stalePeriod: 缓存对象被视为“陈旧”的时间持续时间。如果文件被缓存但一段时间内未被使用,则会被删除。maxNrOfCacheObjects: 允许缓存的文件的最大数量。如果文件数超过此限制,则将删除最长时间未被使用的文件。repo:CacheInfoRepository,用于存储缓存元数据。在Android、iOS和macOS上,默认为CacheObjectProvider,它是一个sqflite实现。在web上,默认为NonStoringObjectProvider。在其他平台上,默认为JsonCacheInfoRepository。fileSystem: 定义缓存文件存储位置的FileSystem对象。fileService: 定义文件获取位置的FileService对象。
通过设置这些属性和参数,可以自定义缓存管理器的行为和性能。
Config实现类
class Config implements def.Config {
Config(
this.cacheKey, {
Duration? stalePeriod,
int? maxNrOfCacheObjects,
CacheInfoRepository? repo,
FileSystem? fileSystem,
FileService? fileService,
}) : stalePeriod = stalePeriod ?? const Duration(days: 30),
maxNrOfCacheObjects = maxNrOfCacheObjects ?? 200,
repo = repo ?? _createRepo(cacheKey),
fileSystem = fileSystem ?? IOFileSystem(cacheKey),
fileService = fileService ?? HttpFileService();
@override
final CacheInfoRepository repo;
@override
final FileSystem fileSystem;
@override
final String cacheKey;
@override
final Duration stalePeriod;
@override
final int maxNrOfCacheObjects;
@override
final FileService fileService;
static CacheInfoRepository _createRepo(String key) {
if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) {
return CacheObjectProvider(databaseName: key);
}
return JsonCacheInfoRepository(databaseName: key);
}
}
这是一个实现了抽象类Config的类Config。在构造函数中,它接受以下参数:
cacheKey:用于存储文件夹和数据库文件名称的键。stalePeriod(可选):定义缓存对象被视为“陈旧”的时间段。当文件被缓存但一段时间没有被使用时,该文件将被删除。默认为30天。maxNrOfCacheObjects(可选):定义缓存允许的最大大小。如果有更多的文件,那些最长时间没有使用的文件将被删除。默认值为200。repo(可选):用于存储缓存元数据的CacheInfoRepository。在Android、iOS和macOS上,这默认为CacheObjectProvider,这是由于其遗留问题使用了sqflite实现。在Web上,这默认为NonStoringObjectProvider。在其他平台上,这默认为JsonCacheInfoRepository。fileSystem(可选):定义缓存文件存储的位置。默认情况下,它使用IOFileSystem,其中cacheKey是文件夹名称。fileService(可选):定义文件获取的位置(例如在线)。默认情况下,它使用HttpFileService。
此外,该类还包含一个静态私有方法_createRepo,用于创建缓存信息存储库。如果在Android、iOS和macOS上,则使用CacheObjectProvider。否则,使用JsonCacheInfoRepository。
FileService抽象类
/// Defines the interface for a file service.
/// Most common file service will be an [HttpFileService], however one can
/// also make something more specialized. For example you could fetch files
/// from other apps or from local storage.
abstract class FileService {
int concurrentFetches = 10;
Future<FileServiceResponse> get(String url, {Map<String, String>? headers});
}
定义了一个文件服务的接口。
最常见的文件服务将是一个 [HttpFileService],但你也可以创建更专门的服务。例如,你可以从其他应用程序或本地存储中获取文件。
HttpFileService(FileService的实现子类)
/// [HttpFileService] is the most common file service and the default for
/// [WebHelper]. One can easily adapt it to use dio or any other http client.
class HttpFileService extends FileService {
final http.Client _httpClient;
HttpFileService({http.Client? httpClient})
: _httpClient = httpClient ?? http.Client();
@override
Future<FileServiceResponse> get(String url,
{Map<String, String>? headers}) async {
final req = http.Request('GET', Uri.parse(url));
if (headers != null) {
req.headers.addAll(headers);
}
final httpResponse = await _httpClient.send(req);
return HttpGetResponse(httpResponse);
}
}
以上代码定义了一个HttpFileService类,它是实现FileService接口的具体实现。这个类主要用于从网络上获取文件,它使用http包提供的Client来发送HTTP请求,获取指定URL的文件。
在类的构造函数中,我们可以传入一个可选的httpClient参数来指定要使用的http客户端。如果没有提供,它将创建一个默认的http.Client()来执行请求。
HttpFileService实现了FileService中定义的get方法,它使用http包的Request类来构建HTTP请求,并通过httpClient.send方法发送请求。返回的响应将被包装在HttpGetResponse对象中,并作为Future<FileServiceResponse>返回。
FileServiceResponse抽象类
/// Defines the interface for a get result of a [FileService].
abstract class FileServiceResponse {
/// [content] is a stream of bytes
Stream<List<int>> get content;
/// [contentLength] is the total size of the content.
/// If the size is not known beforehand contentLength is null.
int? get contentLength;
/// [statusCode] is expected to conform to an http status code.
int get statusCode;
/// Defines till when the cache should be assumed to be valid.
DateTime get validTill;
/// [eTag] is used when asking to update the cache
String? get eTag;
/// Used to save the file on the storage, includes a dot. For example '.jpeg'
String get fileExtension;
}
定义了 [FileService] 获取文件的结果接口。
[content] 是一个字节流。 Stream<List> get content;
[contentLength] 是内容的总大小。 如果大小事先未知,则 contentLength 为 null。
int? get contentLength;
[statusCode] 应符合 HTTP 状态代码的规范。
int get statusCode;
定义了缓存应被认为是有效的截止时间。
DateTime get validTill;
[eTag] 用于在请求更新缓存时使用。
String? get eTag;
用于在存储上保存文件,包括点号。例如 '.jpeg'
String get fileExtension;
HttpGetResponse(FileServiceResponse类的实现)
/// Basic implementation of a [FileServiceResponse] for http requests.
class HttpGetResponse implements FileServiceResponse {
HttpGetResponse(this._response);
final DateTime _receivedTime = clock.now();
final http.StreamedResponse _response;
@override
int get statusCode => _response.statusCode;
String? _header(String name) {
return _response.headers[name];
}
@override
Stream<List<int>> get content => _response.stream;
@override
int? get contentLength => _response.contentLength;
@override
DateTime get validTill {
// Without a cache-control header we keep the file for a week
var ageDuration = const Duration(days: 7);
final controlHeader = _header(HttpHeaders.cacheControlHeader);
if (controlHeader != null) {
final controlSettings = controlHeader.split(',');
for (final setting in controlSettings) {
final sanitizedSetting = setting.trim().toLowerCase();
if (sanitizedSetting == 'no-cache') {
ageDuration = const Duration();
}
if (sanitizedSetting.startsWith('max-age=')) {
var validSeconds = int.tryParse(sanitizedSetting.split('=')[1]) ?? 0;
if (validSeconds > 0) {
ageDuration = Duration(seconds: validSeconds);
}
}
}
}
return _receivedTime.add(ageDuration);
}
@override
String? get eTag => _header(HttpHeaders.etagHeader);
@override
String get fileExtension {
var fileExtension = '';
final contentTypeHeader = _header(HttpHeaders.contentTypeHeader);
if (contentTypeHeader != null) {
final contentType = ContentType.parse(contentTypeHeader);
fileExtension = contentType.fileExtension;
}
return fileExtension;
}
}
HttpGetResponse 是 FileServiceResponse 接口的基本实现,用于处理 HTTP 请求的响应。
它实现了 FileServiceResponse 接口,并提供了实现。
具体来说,它包含了一个私有的 _response 属性,该属性包含了 http.StreamedResponse 对象,以及一个私有的 _receivedTime 属性,表示响应的接收时间。
除此之外,它还实现了接口中定义的方法,包括 statusCode、content、contentLength、validTill、eTag 和 fileExtension。
其中,validTill 方法会解析 Cache-Control 头,并根据其中的指令计算出缓存的有效期,如果缺失 Cache-Control 头,则默认缓存有效期为一周。