123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- using System;
- using System.IO;
- using Best.HTTP.Shared;
- using Best.HTTP.Shared.Logger;
- using Best.HTTP.Shared.PlatformSupport.Memory;
- using UnityEngine;
- namespace Best.HTTP.Caching
- {
- /// <summary>
- /// Represents a writer for caching HTTP response content.
- /// </summary>
- public class HTTPCacheContentWriter
- {
- /// <summary>
- /// Gets the parent HTTPCache instance associated with this content writer.
- /// </summary>
- public HTTPCache Cache { get; private set; }
- /// <summary>
- /// Hash identifying the resource. If <see cref="Write(BufferSegment)"/> fails, it becomes an invalid one.
- /// </summary>
- public Hash128 Hash { get; private set; }
- /// <summary>
- /// Expected length of the content. Has a non-zero value only when the server is sending a "content-length" header.
- /// </summary>
- public ulong ExpectedLength { get; private set; }
- /// <summary>
- /// Number of bytes written to the cache.
- /// </summary>
- public ulong ProcessedLength { get; private set; }
- /// <summary>
- /// Context of this cache writer used for logging.
- /// </summary>
- public LoggingContext Context { get; private set; }
- /// <summary>
- /// Underlying stream the download bytes are written into.
- /// </summary>
- private Stream _contentStream;
- internal HTTPCacheContentWriter(HTTPCache cache, Hash128 hash, Stream contentStream, ulong expectedLength, LoggingContext loggingContext)
- {
- this.Cache = cache;
- this.Hash = hash;
- this._contentStream = contentStream;
- this.ExpectedLength = expectedLength;
- this.Context = loggingContext;
- }
- /// <summary>
- /// Writes content to the underlying stream.
- /// </summary>
- /// <param name="segment"><see cref="BufferSegment"/> holding a reference to the data and containing information about the offset and count of the valid range of data.</param>
- public void Write(BufferSegment segment)
- {
- if (!this.Hash.isValid)
- return;
- try
- {
- this._contentStream?.Write(segment.Data, segment.Offset, segment.Count);
- this.ProcessedLength += (ulong)segment.Count;
- if (this.ProcessedLength > this.ExpectedLength)
- {
- if (!this.Cache.IsThereEnoughSpaceAfterMaintain(this.ProcessedLength, this.Context))
- {
- HTTPManager.Logger.Information(nameof(HTTPCacheContentWriter), $"Not enough space({this.ProcessedLength:N0}) in cache({this.Cache.CacheSize:N0}), even after Maintain!", this.Context);
- this.Cache?.EndCache(this, false, this.Context);
- }
- }
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Warning(nameof(HTTPCacheContentWriter), $"{nameof(Write)}({segment}): {ex}", this.Context);
- // EndCache will call Close, we don't have to in this catch block
- this.Cache?.EndCache(this, false, this.Context);
- }
- }
- /// <summary>
- /// Close the underlying stream and invalidate the hash.
- /// </summary>
- internal void Close()
- {
- this._contentStream?.Close();
- this._contentStream = null;
- // this will set an invalid cache, further HTTPCaching.EndCache calls will return early.
- this.Hash = new Hash128();
- }
- public override string ToString() => $"[{nameof(HTTPCacheContentWriter)} {Hash} {ProcessedLength:N0}]";
- }
- }
|