自定义功能和相关技术
本篇按照如下结构翻译
自定义功能
- 自定义数据仓库
相关技术
- 架构和总体概念
自定义数据仓库
tusdotnet附带一个存储库TusDiskStore,它将文件保存在磁盘上的一个目录中。你可以通过实现以下一个或多个接口(在“接口”这一节中列出来的接口)来实现自己的存储。tusdotnet将自动处理请求并根据用于请求的存储所实现的接口将信息添加到Tus-Extension头部。
请注意有一些方法会在请求执行期间多次调用,这取决于仓储正确的缓存数据。
要实现的最常见接口是ITusStore、ITusCreationStore和ITusReadableStore。这将允许仓储(store)创建和上传文件,并读取文件以进行处理或下载。
接口
以下涉及到的名词请查看我的关于tus协议的翻译。
- ITusStore-这个接口支持核心协议
- ITusChecksumStore - 支持Checksum扩展 (checksum verification of files)
- ITusConcatenationStore - 支持Concatenation扩展(merging multiple files together with a single command)
- ITusCreationStore - 支持Creation扩展 (creating new files)
- ITusCreationDeferLength - 支持Upload-Defer-Length头部 (sub extension of Creation)
- ITusReadableStore - 支持从文件仓储中读取文件 (e.g. for downloads or processing)
- ITusTerminationStore - 支持Termination扩展 (deleting files)
- ITusExpirationStore -支持Expiration扩展 (files expire after a period of time)
ITusStore
必须实现的接口,在Tus-Extension中的值:<none>
这是tus核心协议的接口,自定义的仓储必须实现。
http://tus.io/protocols/resumable-upload.html#core-protocol或请查看我翻译的tus协议的相关内容。
public interface ITusStore { /// <summary> /// 使用提供的流将数据写入文件 /// 如果流的长度超过了上传文件的长度,必须抛出<exception cref="TusStoreException"></exception>异常/// </summary> /// <param name="fileId">要写入的文件Id</param> /// <param name="stream">来自客户端的输入流</param> /// <param name="cancellationToken">取消令牌</param> /// <returns>写入的字节长度</returns> Task<long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken); /// <summary> /// 检索一个文件是否存在 /// </summary> /// <param name="fileId">要检查的文件Id</param> /// <param name="cancellationToken">取消令牌.</param> /// <returns></returns> Task<bool> FileExistAsync(string fileId, CancellationToken cancellationToken); /// <summary> /// Returns the upload length specified when the file was created or null if Defer-Upload-Lenght was used. /// </summary> /// <param name="fileId">The id of the file to check.</param> /// <param name="cancellationToken">Cancellation token to use when cancelling.</param> /// <returns>The upload length of the file</returns> Task<long?> GetUploadLengthAsync(string fileId, CancellationToken cancellationToken); /// <summary> /// Returns the current size of the file a.k.a. the upload offset. /// </summary> /// <param name="fileId">The id of the file to check.</param> /// <param name="cancellationToken">Cancellation token to use when cancelling.</param> /// <returns>The size of the current file</returns> Task<long> GetUploadOffsetAsync(string fileId, CancellationToken cancellationToken); }
ITusChecksumStore
非必须实现的接口,在Tus-Extension中的值:checksum
支持checksum扩展的接口,用于文件校验和(checksum)的检查。
http://tus.io/protocols/resumable-upload.html#checksum 或请查看我翻译的tus协议的相关内容。
public interface ITusChecksumStore { /// <summary> /// Returns a collection of hash algorithms that the store supports (e.g. sha1). /// </summary> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The collection of hash algorithms</returns> Task<IEnumerable<string>> GetSupportedAlgorithmsAsync(CancellationToken cancellationToken); /// <summary> /// Verify that the provided checksum matches the file checksum. /// </summary> /// <param name="fileId">The id of the file to check</param> /// <param name="algorithm">The checksum algorithm to use when checking. This algorithm must be supported by the store.</param> /// <param name="checksum">The checksom to use for verification</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>True if the checksum matches otherwise false</returns> Task<bool> VerifyChecksumAsync(string fileId, string algorithm, byte[] checksum, CancellationToken cancellationToken); }
ITusConcatenationStore
非必须实现的接口,Tus-Extension中的值:concatenation
注意:要实现这个接口必须保证ITusCreationStore也被实现。
这个接口添加了对concatenation扩展的支持,这个扩展的作用在于在一个POST请求中将多个文件串联然后得到一个最终文件。
http://tus.io/protocols/resumable-upload.html#concatenation或查看我关于tus协议的相关翻译
public interface ITusConcatenationStore { /// <summary> /// Returns the type of Upload-Concat header that was used when creating the file. /// Returns null if no Upload-Concat was used. /// </summary> /// <param name="fileId">The file to check</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>FileConcatPartial, FileConcatFinal or null</returns> Task<FileConcat> GetUploadConcatAsync(string fileId, CancellationToken cancellationToken); /// <summary> /// Create a partial file. This method is called when a Upload-Concat header is present and when its value is "partial". /// </summary> /// <param name="uploadLength">The length of the upload in bytes</param> /// <param name="metadata">The Upload-Metadata request header or null if no header was provided</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The id of the newly created file</returns> Task<string> CreatePartialFileAsync(long uploadLength, string metadata, CancellationToken cancellationToken); /// <summary> /// Creates a final file by concatenating multiple files together. This method is called when a Upload-Concat header /// is present with a "final" value. /// </summary> /// <param name="partialFiles">List of file ids to concatenate</param> /// <param name="metadata">The Upload-Metadata request header or null if no header was provided</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The id of the newly created file</returns> Task<string> CreateFinalFileAsync(string[] partialFiles, string metadata, CancellationToken cancellationToken); }
ITusCreationStore
非必须实现的接口,Tus-Extension的值为:creation
这个接口处理tus协议的创建扩展,并用于创建文件引用,稍后可以利用tus核心协议,使用这个创建的文件引用将数据上载。
http://tus.io/protocols/resumable-upload.html#creation 或查看我的tus协议的相关翻译。
public interface ITusCreationStore { /// <summary> /// Create a file upload reference that can later be used to upload data. /// </summary> /// <param name="uploadLength">The length of the upload in bytes</param> /// <param name="metadata">The Upload-Metadata request header or null if no header was provided</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns></returns> Task<string> CreateFileAsync(long uploadLength, string metadata, CancellationToken cancellationToken); /// <summary> /// Get the Upload-Metadata header as it was provided to <code>CreateFileAsync</code>. /// </summary> /// <param name="fileId">The id of the file to get the header for</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The Upload-Metadata header</returns> Task<string> GetUploadMetadataAsync(string fileId, CancellationToken cancellationToken); }
ITusCreationDeferLengthStore
非必须实现的接口,Tus-Extension中的值: creation-defer-length
注意:要实现这个接口必须保证ITusCreationStore接口同时被实现。
creation-defer-length是creation扩展的子扩展,它允许用户在不预先知道上传文件大小的情况下创建文件。
如果实现了这个接口,并且用户选择使用这个特性,那么对CreateFileAsync (ITusCreationStore)和CreatePartialFileAsync (ITusConcatenationStore)的调用将使用-1作为文件长度。
http://tus.io/protocols/resumable-upload.html#upload-defer-length或查看我的tus文档
public interface ITusCreationDeferLengthStore { /// <summary> /// Set the upload length (in bytes) of the provided file. /// </summary> /// <param name="fileId">The id of the file to set the upload length for</param> /// <param name="uploadLength">The length of the upload in bytes</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>Task</returns> Task SetUploadLengthAsync(string fileId, long uploadLength, CancellationToken cancellationToken); }
ITusTerminationStore
非必须实现的接口,Tus-Extensions中的值:termination
这个接口支持了tus协议中的termination扩展,用于删除文件。
http://tus.io/protocols/resumable-upload.html#termination 或查看我的tus文档
public interface ITusTerminationStore { /// <summary> /// Delete a file from the data store. /// </summary> /// <param name="fileId">The id of the file to delete</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>Task</returns> Task DeleteFileAsync(string fileId, CancellationToken cancellationToken); }
ITusReadableStore
非必须实现的接口,Tus-Extension中的值:<none>
ITusReadableStore是一个不属于tus规范的简单接口,它用于帮助从数据存储中读取数据,使下载文件或处理上传文件变得更容易。如何使用该接口的示例可以在我之前翻译的tusdotnet文档的下载文件小结中找到。或者查看英文文档:Downloading files
public interface ITusReadableStore { /// <summary> /// Get the file with the specified id. /// Returns null if the file was not found. /// </summary> /// <param name="fileId">The id of the file to get</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The file or null if the file was not found</returns> Task<ITusFile> GetFileAsync(string fileId, CancellationToken cancellationToken); }
ITusExpirationStore
非必须实现的接口,Tus-Extension中的值:expiration
这个接口实现了expiration扩展,用于服务端删除那些过了一段时间后未完成上传的文件。过期的文件将通过tusdotnet返回404。服务器仍然可以使用仓储(store)的方法访问文件。
http://tus.io/protocols/resumable-upload.html#expiration
https://github.com/smatsson/tusdotnet/wiki/Removing-expired-incomplete-files 介绍了更多关于如何配置文件清理的信息。
public interface ITusExpirationStore { /// <summary> /// Set the expiry date of the provided file. /// This method will be called once during creation if absolute expiration is used. /// This method will be called once per patch request if sliding expiration is used. /// </summary> /// <param name="fileId">The id of the file to update the expiry date for</param> /// <param name="expires">The datetime offset when the file expires</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>Task</returns> Task SetExpirationAsync(string fileId, DateTimeOffset expires, CancellationToken cancellationToken); /// <summary> /// Get the expiry date of the provided file (set by <code>SetExpirationAsync</code>). /// If the datetime offset returned has passed an error will be returned to the client. /// If no expiry date exist for the file, this method returns null. /// </summary> /// <param name="fileId">The id of the file to get the expiry date for</param> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns></returns> Task<DateTimeOffset?> GetExpirationAsync(string fileId, CancellationToken cancellationToken); /// <summary> /// Returns a list of ids of incomplete files that have expired. /// This method can be used to do batch processing of incomplete, expired files before removing them. /// </summary> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>A list of ids of incomplete files that have expired</returns> Task<IEnumerable<string>> GetExpiredFilesAsync(CancellationToken cancellationToken); /// <summary> /// Remove all incomplete files that have expired. /// </summary> /// <param name="cancellationToken">Cancellation token to use when cancelling</param> /// <returns>The number of files that were removed</returns> Task<int> RemoveExpiredFilesAsync(CancellationToken cancellationToken); }
架构和总体概念
这部分描述了tusdonet的架构和它的总体概念。
tusdotnet包含了三个主要的部分:
- Tus的中间件
- 一个用于配置的对象
- 一个数据存储库
Tus中间件
这是负责处理所有请求并返回正确响应的OWIN中间件。中间件的功能取决于所使用的数据存储所实现的接口。
要设置中间件,请使用UseTus扩展方法并为其提供配置工厂。使用这种方法,tusdotnet支持为不同的请求(例如不同的用户、租户等)使用不同的配置。
中间件将转发它不能处理的所有请求,例如GET请求或其他缺少Tus-Resumable头的请求。这样,即使客户机不支持tus协议,开发人员仍然可以处理上传。
用于配置的对象
用于配置的对象告诉Tus中间件有哪些选项可用。它目前支持设置要侦听的URL、要使用的数据存储和在请求处理期间运行的自定义回调。
相关信息在这里:Configure tusdotnet 或者你可以查看我翻译的文档。
数据存储库
数据存储是tusdotnet存储数据的地方,也是决定运行tusdotnet的服务器功能的地方。存储库可以实现许多接口,每个接口都赋予系统更多的功能。tusdotnet附带了一个存储库实现TusDiskStore,这是一个简单的存储,将数据保存在服务器磁盘上的文件夹中。支持自定义数据(Custom data stores)存储。