prometheus-net
84 строки · 3.8 Кб
1// Copyright (c) .NET Foundation. All rights reserved.
2// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3// Simplified for prometheus-net for dependency reduction reasons.
4
5using System.Diagnostics.CodeAnalysis;6using System.Net;7using System.Net.Http.Headers;8
9namespace Prometheus;10
11/// <summary>
12/// Provides an <see cref="HttpContent"/> implementation that exposes an output <see cref="Stream"/>
13/// which can be written to directly. The ability to push data to the output stream differs from the
14/// <see cref="StreamContent"/> where data is pulled and not pushed.
15/// </summary>
16sealed class PushStreamContentInternal : HttpContent17{
18private readonly Func<Stream, HttpContent, TransportContext?, Task> _onStreamAvailable;19
20private static readonly MediaTypeHeaderValue OctetStreamHeaderValue = MediaTypeHeaderValue.Parse("application/octet-stream");21
22/// <summary>23/// Initializes a new instance of the <see cref="PushStreamContentInternal"/> class with the given <see cref="MediaTypeHeaderValue"/>.24/// </summary>25public PushStreamContentInternal(Func<Stream, HttpContent, TransportContext?, Task> onStreamAvailable, MediaTypeHeaderValue mediaType)26{27_onStreamAvailable = onStreamAvailable;28Headers.ContentType = mediaType ?? OctetStreamHeaderValue;29}30
31/// <summary>32/// When this method is called, it calls the action provided in the constructor with the output33/// stream to write to. Once the action has completed its work it closes the stream which will34/// close this content instance and complete the HTTP request or response.35/// </summary>36/// <param name="stream">The <see cref="Stream"/> to which to write.</param>37/// <param name="context">The associated <see cref="TransportContext"/>.</param>38/// <returns>A <see cref="Task"/> instance that is asynchronously serializing the object's content.</returns>39[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exception is passed as task result.")]40protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context)41{42TaskCompletionSource<bool> serializeToStreamTask = new TaskCompletionSource<bool>();43
44Stream wrappedStream = new CompleteTaskOnCloseStream(stream, serializeToStreamTask);45await _onStreamAvailable(wrappedStream, this, context);46
47// wait for wrappedStream.Close/Dispose to get called.48await serializeToStreamTask.Task;49}50
51/// <summary>52/// Computes the length of the stream if possible.53/// </summary>54/// <param name="length">The computed length of the stream.</param>55/// <returns><c>true</c> if the length has been computed; otherwise <c>false</c>.</returns>56protected override bool TryComputeLength(out long length)57{58// We can't know the length of the content being pushed to the output stream.59length = -1;60return false;61}62
63internal class CompleteTaskOnCloseStream : DelegatingStreamInternal64{65private TaskCompletionSource<bool> _serializeToStreamTask;66
67public CompleteTaskOnCloseStream(Stream innerStream, TaskCompletionSource<bool> serializeToStreamTask)68: base(innerStream)69{70_serializeToStreamTask = serializeToStreamTask;71}72
73[SuppressMessage(74"Microsoft.Usage",75"CA2215:Dispose methods should call base class dispose",76Justification = "See comments, this is intentional.")]77protected override void Dispose(bool disposing)78{79// We don't dispose the underlying stream because we don't own it. Dispose in this case just signifies80// that the user's action is finished.81_serializeToStreamTask.TrySetResult(true);82}83}84}
85