Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ClientChunkRecord.cs
1using System;
3using System.Threading;
4using System.Threading.Tasks;
5using Waher.Events;
7
9{
10 internal class ClientChunkRecord : ChunkRecord
11 {
12 private readonly HttpxClient client;
13 private readonly HttpxResponseEventArgs e;
14 private readonly object state;
15 private readonly string streamId;
16 private readonly string from;
17 private readonly string to;
18 private readonly string endpointReference;
19 private readonly bool e2e;
20 private readonly EventHandlerAsync<HttpxResponseDataEventArgs> dataCallback;
21 private readonly IE2eSymmetricCipher symmetricCipher;
22 private readonly SemaphoreSlim synchObj = new SemaphoreSlim(1);
23 private SortedDictionary<int, Chunk> chunks = null;
24 private HttpResponse response;
25 private int nextChunk = 0;
26 private bool disposed = false;
27
28 internal ClientChunkRecord(HttpxClient Client, HttpxResponseEventArgs e, HttpResponse Response,
29 EventHandlerAsync<HttpxResponseDataEventArgs> DataCallback, object State, string StreamId, string From, string To, bool E2e,
30 string EndpointReference, IE2eSymmetricCipher SymmetricCipher)
31 : base()
32 {
33 this.client = Client;
34 this.e = e;
35 this.response = Response;
36 this.dataCallback = DataCallback;
37 this.state = State;
38 this.streamId = StreamId;
39 this.from = From;
40 this.to = To;
41 this.e2e = E2e;
42 this.endpointReference = EndpointReference;
43 this.symmetricCipher = SymmetricCipher;
44 }
45
46 public string From => this.from;
47 public string To => this.to;
48 public bool E2e => this.e2e;
49 public string EndpointReference => this.endpointReference;
50 public IE2eSymmetricCipher SymmetricCipher => this.symmetricCipher;
51
52 internal override async Task<bool> ChunkReceived(int Nr, bool Last, bool ConstantBuffer, byte[] Data)
53 {
54 if (this.disposed)
55 throw new ObjectDisposedException(nameof(ClientChunkRecord));
56
57 await this.synchObj.WaitAsync();
58 try
59 {
60 if (Nr == this.nextChunk)
61 {
62 if (Data.Length > 0 || Last)
63 {
64 HttpxResponseDataEventArgs e = new HttpxResponseDataEventArgs(null, ConstantBuffer, Data, this.streamId, Last, this.state);
65 if (!await this.dataCallback.Raise(this.client, e, false))
66 {
67 await this.client.CancelTransfer(this.e.From, this.streamId);
68 return false;
69 }
70 }
71
72 this.nextChunk++;
73
74 if (Last)
75 await this.DoneLocked();
76 else
77 {
78 while (!(this.chunks is null))
79 {
80 if (this.chunks.Count == 0)
81 this.chunks = null;
82 else
83 {
84 foreach (Chunk Chunk in this.chunks.Values)
85 {
86 if (Chunk.Nr == this.nextChunk)
87 {
88 HttpxResponseDataEventArgs e = new HttpxResponseDataEventArgs(null, Chunk.ConstantBuffer, Chunk.Data, this.streamId, Chunk.Last, this.state);
89 if (!await this.dataCallback.Raise(this.client, e, false))
90 return false;
91
92 this.nextChunk++;
93 this.chunks.Remove(Chunk.Nr);
94
95 if (Chunk.Last)
96 await this.DoneLocked();
97
98 break;
99 }
100 else
101 return true;
102 }
103 }
104 }
105 }
106 }
107 else if (Nr > this.nextChunk)
108 {
109 this.chunks ??= new SortedDictionary<int, Chunk>();
110 this.chunks[Nr] = new Chunk(Nr, Last, ConstantBuffer, Data);
111 }
112
113 return true;
114 }
115 finally
116 {
117 this.synchObj.Release();
118 }
119 }
120
121 private async Task DoneLocked()
122 {
123 if (!(this.response is null))
124 {
125 try
126 {
127 await this.response.DisposeAsync();
128 }
129 catch (Exception ex)
130 {
131 Log.Exception(ex);
132 }
133 }
134
135 this.chunks?.Clear();
136 }
137
138 internal override async Task Fail(string Message)
139 {
140 if (this.disposed)
141 throw new ObjectDisposedException(nameof(ClientChunkRecord));
142
143 await this.synchObj.WaitAsync();
144 try
145 {
146 if (this.response is null)
147 return;
148
149 HttpxResponseDataEventArgs e = new HttpxResponseDataEventArgs(null, true, Array.Empty<byte>(), this.streamId, true, this.state);
150 await this.dataCallback.Raise(this.client, e, false);
151
152 if (!this.response.HeaderSent)
153 await this.response.SendResponse(new InternalServerErrorException(Message));
154
155 await this.client.CancelTransfer(this.e.From, this.streamId);
156
157 await this.DoneLocked();
158 }
159 finally
160 {
161 this.synchObj.Release();
162 }
163 }
164
165 public override async Task DisposeAsync()
166 {
167 if (!this.disposed)
168 {
169 this.disposed = true;
170
171 await this.synchObj.WaitAsync();
172 try
173 {
174 if (!(this.response is null))
175 {
176 await this.response.DisposeAsync();
177 this.response = null;
178 }
179
180 this.chunks?.Clear();
181 this.chunks = null;
182 }
183 finally
184 {
185 this.synchObj.Dispose();
186 }
187 }
188 }
189 }
190}
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:14
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1657
Represets a response of an HTTP client request.
Definition: HttpResponse.cs:23
async Task DisposeAsync()
Closes the connection and disposes of all resources.
async Task SendResponse()
Sends the response back to the client. If the resource is synchronous, there's no need to call this m...
bool HeaderSent
If the header has been sent.
The server encountered an unexpected condition which prevented it from fulfilling the request.