16 |
16 |
using System.Threading;
|
17 |
17 |
using System.Web;
|
18 |
18 |
using System.Security.Cryptography.X509Certificates;
|
|
19 |
using log4net;
|
19 |
20 |
|
20 |
21 |
namespace ServerApp.Connection
|
21 |
22 |
{
|
22 |
|
|
|
23 |
/// <summary>
|
|
24 |
/// Class taking care of receiving the client side requests and sending back responses
|
|
25 |
/// </summary>
|
23 |
26 |
public class ConnectionListenerAsync
|
24 |
27 |
{
|
|
28 |
// logger class instance
|
|
29 |
private static readonly ILog logger = LogManager.GetLogger(typeof(ConnectionListenerAsync));
|
|
30 |
|
|
31 |
// the port to listen on
|
25 |
32 |
private readonly int PORT;
|
|
33 |
|
|
34 |
// the predictor class instance
|
26 |
35 |
private IPredictionController predictionController;
|
27 |
36 |
|
28 |
37 |
public ConnectionListenerAsync(int port, IPredictionController predictionController)
|
... | ... | |
31 |
40 |
this.predictionController = predictionController;
|
32 |
41 |
}
|
33 |
42 |
|
34 |
|
|
|
43 |
/// <summary>
|
|
44 |
/// Starts asynchronously waiting for requests. Handles them when they come.
|
|
45 |
/// </summary>
|
35 |
46 |
public void StartListening()
|
36 |
47 |
{
|
37 |
48 |
string ip = GetLocalIPAddress();
|
38 |
|
Console.WriteLine("ip : " + ip);
|
|
49 |
//Console.WriteLine("ip : " + ip);
|
39 |
50 |
HttpListener listener = new HttpListener();
|
40 |
51 |
listener.Prefixes.Add($"https://*:{PORT}/");
|
41 |
52 |
//listener.Prefixes.Add($"http://*:{PORT}/");
|
... | ... | |
51 |
62 |
|
52 |
63 |
listener.Start();
|
53 |
64 |
|
54 |
|
Console.WriteLine("Listening...");
|
|
65 |
//Console.WriteLine("Listening...");
|
|
66 |
logger.Info("Started listening at ip: " + ip + ", port: " + PORT);
|
55 |
67 |
|
56 |
68 |
|
57 |
69 |
var result = listener.BeginGetContext(ListenerCallback, listener);
|
... | ... | |
70 |
82 |
private void HandleRequest(HttpListenerContext context)
|
71 |
83 |
{
|
72 |
84 |
|
73 |
|
Console.WriteLine("Handling request.");
|
|
85 |
//Console.WriteLine("Handling request.");
|
|
86 |
logger.Debug("Handling request.");
|
74 |
87 |
// Obtain a request object.
|
75 |
88 |
HttpListenerRequest request = context.Request;
|
76 |
89 |
// Obtain a response object.
|
... | ... | |
89 |
102 |
// Construct a response.
|
90 |
103 |
if (context.Request.HttpMethod == "GET") // when client says download
|
91 |
104 |
{
|
92 |
|
Console.WriteLine("received GET request");
|
|
105 |
logger.Info("received GET request");
|
93 |
106 |
|
94 |
107 |
string text;
|
95 |
108 |
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
... | ... | |
101 |
114 |
}
|
102 |
115 |
else if (context.Request.HttpMethod == "POST") // when client says upload
|
103 |
116 |
{
|
104 |
|
Console.WriteLine("received POST request");
|
|
117 |
logger.Info("received POST request");
|
105 |
118 |
string text;
|
106 |
119 |
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
107 |
120 |
text = reader.ReadToEnd();
|
... | ... | |
113 |
126 |
}
|
114 |
127 |
else
|
115 |
128 |
{
|
116 |
|
Console.WriteLine("received request other than GET or POST");
|
|
129 |
logger.Warn("received request other than GET or POST");
|
117 |
130 |
|
118 |
131 |
}
|
119 |
132 |
|
... | ... | |
121 |
134 |
System.IO.Stream output = response.OutputStream;
|
122 |
135 |
if (!string.IsNullOrEmpty(responseString))
|
123 |
136 |
{
|
124 |
|
Console.WriteLine("Response is not null or empty, sending it to the client.");
|
|
137 |
logger.Debug("Response is not null or empty, sending it to the client.");
|
125 |
138 |
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
|
126 |
139 |
|
127 |
140 |
// Get a response stream and write the response to it.
|
... | ... | |
130 |
143 |
}
|
131 |
144 |
else
|
132 |
145 |
{
|
133 |
|
Console.WriteLine("Response was null or empty, not sending anything.");
|
|
146 |
logger.Debug("Response was null or empty, not sending anything.");
|
134 |
147 |
}
|
135 |
148 |
|
136 |
149 |
|
... | ... | |
138 |
151 |
//output.Close();
|
139 |
152 |
response.Close();
|
140 |
153 |
|
141 |
|
Console.WriteLine("At the end of HandleRequest");
|
|
154 |
logger.Debug("At the end of HandleRequest");
|
142 |
155 |
}
|
143 |
156 |
|
144 |
157 |
|
145 |
|
|
146 |
158 |
private void ListenerCallback(IAsyncResult result)
|
147 |
159 |
{
|
148 |
|
Console.WriteLine("in ListenerCallback");
|
|
160 |
logger.Debug("in ListenerCallback");
|
149 |
161 |
HttpListener listener = (HttpListener)result.AsyncState;
|
150 |
162 |
|
151 |
163 |
// Call EndGetContext to complete the asynchronous operation.
|
... | ... | |
175 |
187 |
// Construct a response.
|
176 |
188 |
if (context.Request.HttpMethod == "GET") // when client says download
|
177 |
189 |
{
|
178 |
|
Console.WriteLine("received GET request");
|
|
190 |
logger.Info("received GET request");
|
179 |
191 |
|
180 |
192 |
string text;
|
181 |
193 |
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
... | ... | |
187 |
199 |
}
|
188 |
200 |
else if (context.Request.HttpMethod == "POST") // when client says upload
|
189 |
201 |
{
|
190 |
|
Console.WriteLine("received POST request");
|
|
202 |
logger.Info("received POST request");
|
191 |
203 |
string text;
|
192 |
204 |
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
193 |
205 |
text = reader.ReadToEnd();
|
... | ... | |
199 |
211 |
}
|
200 |
212 |
else
|
201 |
213 |
{
|
202 |
|
Console.WriteLine("received request other than GET or POST");
|
|
214 |
logger.Warn("received request other than GET or POST");
|
203 |
215 |
}
|
204 |
216 |
|
205 |
217 |
|
206 |
218 |
System.IO.Stream output = response.OutputStream;
|
207 |
219 |
if (!string.IsNullOrEmpty(responseString))
|
208 |
220 |
{
|
209 |
|
Console.WriteLine("Response is not null or empty, sending it to the client.");
|
|
221 |
logger.Debug("Response is not null or empty, sending it to the client.");
|
210 |
222 |
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
|
211 |
223 |
|
212 |
224 |
// Get a response stream and write the response to it.
|
... | ... | |
215 |
227 |
}
|
216 |
228 |
else
|
217 |
229 |
{
|
218 |
|
Console.WriteLine("Response was null or empty, not sending anything.");
|
|
230 |
logger.Debug("Response was null or empty, not sending anything.");
|
219 |
231 |
}
|
220 |
232 |
|
221 |
233 |
|
... | ... | |
223 |
235 |
output.Close();
|
224 |
236 |
response.Close();
|
225 |
237 |
|
226 |
|
Console.WriteLine("At the end of ListenerCallback");
|
|
238 |
logger.Debug("At the end of ListenerCallback");
|
227 |
239 |
|
228 |
240 |
}
|
229 |
241 |
|
... | ... | |
241 |
253 |
//return xml;
|
242 |
254 |
|
243 |
255 |
|
244 |
|
Console.WriteLine("Constructing a response for GET request.");
|
245 |
|
Console.WriteLine("Request string: ");
|
246 |
|
Console.WriteLine(requestString);
|
|
256 |
logger.Info("Constructing a response for GET request.");
|
|
257 |
logger.Info("Request string: ");
|
|
258 |
logger.Info(requestString);
|
247 |
259 |
|
248 |
260 |
|
249 |
261 |
|
250 |
262 |
// prepare the type:
|
251 |
|
Request newRequest = new Request();
|
|
263 |
//Request newRequest = new Request();
|
252 |
264 |
Request requestDeserialized = null;
|
253 |
265 |
try
|
254 |
266 |
{
|
255 |
|
Console.WriteLine("Trying to deserialize xml request.");
|
|
267 |
logger.Info("Trying to deserialize xml request.");
|
256 |
268 |
requestDeserialized = XmlCommunication.Deserialize<Request>(requestString);
|
257 |
269 |
}
|
258 |
270 |
catch
|
259 |
271 |
{
|
260 |
|
Console.WriteLine("wrong format of request!");
|
|
272 |
logger.Warn("Wrong format of request!");
|
261 |
273 |
|
262 |
274 |
// don't bother to send anything:
|
263 |
275 |
return string.Empty;
|
... | ... | |
265 |
277 |
|
266 |
278 |
|
267 |
279 |
// get the prediction from the model:
|
268 |
|
Console.WriteLine("Getting the prediction from the predictor.");
|
269 |
|
Console.WriteLine("Deserialized request is null? : " + requestDeserialized == null);
|
|
280 |
logger.Info("Getting the prediction from the predictor.");
|
|
281 |
logger.Debug("Deserialized request is null? : " + requestDeserialized == null);
|
270 |
282 |
Response responsePrediction = predictionController.Predict(requestDeserialized);
|
271 |
283 |
|
272 |
284 |
string constructedXml = XmlCommunication.Serialize(responsePrediction);
|
273 |
|
Console.WriteLine("Constructed response:");
|
274 |
|
Console.WriteLine(constructedXml);
|
|
285 |
logger.Info("Constructed response:");
|
|
286 |
logger.Info(constructedXml);
|
275 |
287 |
|
276 |
288 |
// build the xml from the prediction: - TODO mbe an exception can happen here as well? - it shouldnt
|
277 |
289 |
return constructedXml;//XmlCommunication.Serialize(responsePrediction);
|
... | ... | |
281 |
293 |
|
282 |
294 |
private string ConstructPOSTResponse(string requestString)
|
283 |
295 |
{
|
284 |
|
Console.WriteLine("Constructing a response for POST request.");
|
285 |
|
Console.WriteLine("Request string: ");
|
286 |
|
Console.WriteLine(requestString);
|
|
296 |
logger.Info("Constructing a response for POST request.");
|
|
297 |
logger.Info("Request string: ");
|
|
298 |
logger.Info(requestString);
|
287 |
299 |
|
288 |
300 |
|
289 |
301 |
|
290 |
302 |
// prepare the type:
|
291 |
|
Request newRequest = new Request();
|
|
303 |
//Request newRequest = new Request();
|
292 |
304 |
Request requestDeserialized = null;
|
293 |
305 |
try
|
294 |
306 |
{
|
295 |
|
Console.WriteLine("Trying to deserialize xml request.");
|
|
307 |
logger.Info("Trying to deserialize xml request.");
|
296 |
308 |
requestDeserialized = XmlCommunication.Deserialize<Request>(requestString);
|
297 |
309 |
}
|
298 |
310 |
catch
|
299 |
311 |
{
|
300 |
|
Console.WriteLine("wrong format of request!");
|
|
312 |
logger.Warn("wrong format of request!");
|
301 |
313 |
|
302 |
314 |
// don't bother to send anything:
|
303 |
315 |
return string.Empty;
|
... | ... | |
305 |
317 |
|
306 |
318 |
|
307 |
319 |
// get the prediction from the model:
|
308 |
|
Console.WriteLine("Getting the prediction from the predictor.");
|
309 |
|
Console.WriteLine("Deserialized request is null? : " + requestDeserialized == null);
|
|
320 |
logger.Info("Getting the prediction from the predictor.");
|
|
321 |
logger.Debug("Deserialized request is null? : " + requestDeserialized == null);
|
310 |
322 |
Response responsePrediction = predictionController.Predict(requestDeserialized);
|
311 |
323 |
|
312 |
324 |
|
313 |
325 |
string constructedXml = XmlCommunication.Serialize(responsePrediction);
|
314 |
|
Console.WriteLine("Constructed response:");
|
315 |
|
Console.WriteLine(constructedXml);
|
|
326 |
logger.Info("Constructed response:");
|
|
327 |
logger.Info(constructedXml);
|
316 |
328 |
|
317 |
329 |
// build the xml from the prediction: - TODO mbe an exception can happen here as well? - it shouldnt
|
318 |
330 |
return constructedXml;//XmlCommunication.Serialize(responsePrediction);
|
... | ... | |
336 |
348 |
}
|
337 |
349 |
}
|
338 |
350 |
|
339 |
|
|
340 |
|
|
341 |
|
|
342 |
|
|
343 |
|
|
344 |
|
|
345 |
|
|
346 |
|
|
347 |
|
|
348 |
|
|
349 |
|
|
350 |
|
|
351 |
|
|
352 |
|
|
353 |
|
|
354 |
|
|
355 |
|
|
356 |
|
|
357 |
|
|
358 |
|
|
359 |
|
|
360 |
|
|
361 |
|
|
362 |
|
|
363 |
|
// TODO clean this up --->
|
364 |
|
// -----------------------------------------------------------------------------
|
365 |
|
|
366 |
|
public class ConnectionListener
|
367 |
|
{
|
368 |
|
private readonly int PORT;
|
369 |
|
private IPredictionController predictionController;
|
370 |
|
|
371 |
|
public ConnectionListener(int port, IPredictionController predictionController)
|
372 |
|
{
|
373 |
|
this.PORT = port;
|
374 |
|
this.predictionController = predictionController;
|
375 |
|
}
|
376 |
|
|
377 |
|
|
378 |
|
public void StartListening()
|
379 |
|
{
|
380 |
|
string ip = GetLocalIPAddress();
|
381 |
|
Console.WriteLine("ip : " + ip);
|
382 |
|
HttpListener server = new HttpListener();
|
383 |
|
//server.Prefixes.Add($"https://{ip}:{PORT}/");
|
384 |
|
server.Prefixes.Add($"http://localhost:{PORT}/");
|
385 |
|
|
386 |
|
server.Start();
|
387 |
|
|
388 |
|
Console.WriteLine("Listening...");
|
389 |
|
|
390 |
|
while (true)
|
391 |
|
{
|
392 |
|
Console.WriteLine("Waiting for a client request...");
|
393 |
|
|
394 |
|
//ThreadPool.QueueUserWorkItem(Process, server.GetContext());
|
395 |
|
HttpListenerContext context = server.GetContext();
|
396 |
|
|
397 |
|
|
398 |
|
|
399 |
|
if (context.Request.HttpMethod == "GET") // when client says download
|
400 |
|
{
|
401 |
|
Console.WriteLine("received GET request");
|
402 |
|
|
403 |
|
HttpListenerResponse response = context.Response;
|
404 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
405 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
406 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
407 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
408 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
409 |
|
|
410 |
|
|
411 |
|
|
412 |
|
//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
|
413 |
|
// if (page == string.Empty)
|
414 |
|
// page = "test.txt";
|
415 |
|
//
|
416 |
|
// TextReader tr = new StreamReader(page);
|
417 |
|
// string msg = tr.ReadToEnd();
|
418 |
|
|
419 |
|
int rand = new Random().Next(1, 10);
|
420 |
|
string msg = "This is a response from the server :) " + rand;
|
421 |
|
|
422 |
|
Response xmlResp = Response.Randomize();
|
423 |
|
var xml = XmlCommunication.Serialize(xmlResp);
|
424 |
|
//Console.WriteLine(xml);
|
425 |
|
|
426 |
|
msg = xml;
|
427 |
|
|
428 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
429 |
|
|
430 |
|
response.ContentLength64 = buffer.Length;
|
431 |
|
Stream st = response.OutputStream;
|
432 |
|
st.Write(buffer, 0, buffer.Length);
|
433 |
|
|
434 |
|
|
435 |
|
context.Response.Close();
|
436 |
|
}
|
437 |
|
|
438 |
|
else if (context.Request.HttpMethod == "POST") // when client says upload
|
439 |
|
{
|
440 |
|
Console.WriteLine("received POST request");
|
441 |
|
|
442 |
|
string text;
|
443 |
|
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
444 |
|
text = reader.ReadToEnd();
|
445 |
|
Console.WriteLine("Received request:");
|
446 |
|
string requestXML = HttpUtility.UrlDecode(text);
|
447 |
|
Console.WriteLine(requestXML);
|
448 |
|
|
449 |
|
// prepare the type:
|
450 |
|
Request newRequest = new Request();
|
451 |
|
Request requestDeserialized = null;
|
452 |
|
try
|
453 |
|
{
|
454 |
|
requestDeserialized = XmlCommunication.Deserialize<Request>(requestXML);
|
455 |
|
}
|
456 |
|
catch
|
457 |
|
{
|
458 |
|
Console.WriteLine("wrong format of request!");
|
459 |
|
|
460 |
|
// don't bother to send anything:
|
461 |
|
context.Response.Close();
|
462 |
|
continue;
|
463 |
|
}
|
464 |
|
|
465 |
|
|
466 |
|
// response headers:
|
467 |
|
HttpListenerResponse response = context.Response;
|
468 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
469 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
470 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
471 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
472 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
473 |
|
|
474 |
|
// get the prediction from the model:
|
475 |
|
Response responsePrediction = predictionController.Predict(requestDeserialized);
|
476 |
|
|
477 |
|
int rand = new Random().Next(1, 10);
|
478 |
|
string msg = "OK " + rand;
|
479 |
|
|
480 |
|
// build the xml from the prediction: - TODO mbe an exception can happen here as well? - it shouldnt
|
481 |
|
msg = XmlCommunication.Serialize(responsePrediction);
|
482 |
|
|
483 |
|
|
484 |
|
// send the response:
|
485 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
486 |
|
response.ContentLength64 = buffer.Length;
|
487 |
|
Stream st = response.OutputStream;
|
488 |
|
st.Write(buffer, 0, buffer.Length);
|
489 |
|
|
490 |
|
// close
|
491 |
|
context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
|
492 |
|
}
|
493 |
|
else
|
494 |
|
{
|
495 |
|
Console.WriteLine("received request other than GET or POST");
|
496 |
|
Console.WriteLine("method: " + context.Request.HttpMethod);
|
497 |
|
Console.WriteLine("headers: " + context.Request.Headers);
|
498 |
|
Console.WriteLine("whole request?: " + context.Request);
|
499 |
|
Console.WriteLine("user: " + context.User);
|
500 |
|
|
501 |
|
|
502 |
|
|
503 |
|
//HttpListenerResponse response = context.Response;
|
504 |
|
//response.AddHeader("Access-Control-Allow-Credentials", "true");
|
505 |
|
//response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
506 |
|
//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
|
507 |
|
//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
508 |
|
//response.AddHeader("Access-Control-Allow-Origin", "*");
|
509 |
|
|
510 |
|
//string msg = "Preflight check? ";
|
511 |
|
|
512 |
|
//byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
513 |
|
|
514 |
|
//response.ContentLength64 = buffer.Length;
|
515 |
|
//Stream st = response.OutputStream;
|
516 |
|
//st.Write(buffer, 0, buffer.Length);
|
517 |
|
|
518 |
|
|
519 |
|
//context.Response.Close(); // ??
|
520 |
|
|
521 |
|
}
|
522 |
|
}
|
523 |
|
}
|
524 |
|
|
525 |
|
private string GetLocalIPAddress()
|
526 |
|
{
|
527 |
|
var host = Dns.GetHostEntry(Dns.GetHostName());
|
528 |
|
foreach (var ip in host.AddressList)
|
529 |
|
{
|
530 |
|
if (ip.AddressFamily == AddressFamily.InterNetwork)
|
531 |
|
{
|
532 |
|
return ip.ToString();
|
533 |
|
}
|
534 |
|
}
|
535 |
|
throw new Exception("No network adapters with an IPv4 address in the system!");
|
536 |
|
}
|
537 |
|
|
538 |
|
}
|
539 |
|
|
540 |
|
|
541 |
|
|
542 |
|
|
543 |
|
|
544 |
|
|
545 |
|
|
546 |
|
|
547 |
|
|
548 |
|
|
549 |
|
|
550 |
|
|
551 |
|
|
552 |
|
|
553 |
|
|
554 |
|
|
555 |
|
|
556 |
|
|
557 |
|
// ---------------------------------------------------------------------------
|
558 |
|
|
559 |
|
|
560 |
|
class ClientService
|
561 |
|
{
|
562 |
|
public static readonly int MAX_IDS = 1000000; // ??
|
563 |
|
public static int IDs = 0;
|
564 |
|
public int UniqueID;
|
565 |
|
public Request ClientRequest;
|
566 |
|
public Response ClientResponse;
|
567 |
|
}
|
568 |
|
|
569 |
|
public class ConnectionListenerQueue
|
570 |
|
{
|
571 |
|
private readonly int PORT;
|
572 |
|
private ConcurrentDictionary<int, ClientService> readyRequests;
|
573 |
|
private ConcurrentQueue<ClientService> waitingRequests;
|
574 |
|
|
575 |
|
|
576 |
|
public ConnectionListenerQueue(int port)
|
577 |
|
{
|
578 |
|
this.PORT = port;
|
579 |
|
}
|
580 |
|
|
581 |
|
|
582 |
|
private void RequestHandler()
|
583 |
|
{
|
584 |
|
while (true)
|
585 |
|
{
|
586 |
|
if (!waitingRequests.IsEmpty)
|
587 |
|
{
|
588 |
|
Console.WriteLine("handling a request for 10s...");
|
589 |
|
ClientService nextService;
|
590 |
|
bool deqResultOk = waitingRequests.TryDequeue(out nextService);
|
591 |
|
// nextService has ID and request filled out
|
592 |
|
Thread.Sleep(10000);
|
593 |
|
|
594 |
|
Console.WriteLine("finished building response, adding it to the dictionary...");
|
595 |
|
//ClientService service = new ClientService();
|
596 |
|
//service.UniqueID = GetNextID();
|
597 |
|
//service.ClientRequest = Request.Randomize();
|
598 |
|
nextService.ClientResponse = Response.Randomize();
|
599 |
|
bool resultOk = readyRequests.TryAdd(nextService.UniqueID, nextService);
|
600 |
|
if (!resultOk)
|
601 |
|
{
|
602 |
|
Console.WriteLine("ID " + nextService.UniqueID + " is being used!");
|
603 |
|
// do nothing? - keep it in the queue and let the client try later perhaps?
|
604 |
|
}
|
605 |
|
else
|
606 |
|
{
|
607 |
|
// added to dictionary
|
608 |
|
// -> remove it from the queue
|
609 |
|
|
610 |
|
}
|
611 |
|
}
|
612 |
|
else
|
613 |
|
{
|
614 |
|
Thread.Sleep(100); // ??
|
615 |
|
}
|
616 |
|
|
617 |
|
}
|
618 |
|
|
619 |
|
|
620 |
|
}
|
621 |
|
|
622 |
|
private int GetNextID()
|
623 |
|
{
|
624 |
|
int id = (ClientService.IDs++) % ClientService.MAX_IDS; // we presume that after a million requests, the first ids are free again, if not, tough luck
|
625 |
|
return id;
|
626 |
|
}
|
627 |
|
|
628 |
|
public void StartListening()
|
629 |
|
{
|
630 |
|
string ip = GetLocalIPAddress();
|
631 |
|
Console.WriteLine("ip : " + ip);
|
632 |
|
HttpListener server = new HttpListener();
|
633 |
|
//server.Prefixes.Add($"https://{ip}:{PORT}/");
|
634 |
|
server.Prefixes.Add($"http://localhost:{PORT}/");
|
635 |
|
|
636 |
|
server.Start();
|
637 |
|
|
638 |
|
Console.WriteLine("Listening...");
|
639 |
|
|
640 |
|
waitingRequests = new ConcurrentQueue<ClientService>();
|
641 |
|
readyRequests = new ConcurrentDictionary<int, ClientService>();
|
642 |
|
|
643 |
|
|
644 |
|
Thread requestHandlerThread = new Thread(RequestHandler);
|
645 |
|
requestHandlerThread.Start();
|
646 |
|
|
647 |
|
while (true)
|
648 |
|
{
|
649 |
|
Console.WriteLine("Waiting for a client request...");
|
650 |
|
//Console.ReadLine();
|
651 |
|
|
652 |
|
HttpListenerContext context = server.GetContext();
|
653 |
|
//Thread.Sleep(10000);
|
654 |
|
|
655 |
|
//IAsyncResult result = server.BeginGetContext(new AsyncCallback(ListenerCallback), server);
|
656 |
|
//Console.WriteLine("Waiting for request to be processed asyncronously.");
|
657 |
|
//result.AsyncWaitHandle.WaitOne();
|
658 |
|
//Console.WriteLine("Request processed asyncronously.");
|
659 |
|
|
660 |
|
|
661 |
|
|
662 |
|
if (context.Request.HttpMethod == "GET") // when client says download
|
663 |
|
{
|
664 |
|
Console.WriteLine("received GET request");
|
665 |
|
|
666 |
|
HttpListenerResponse response = context.Response;
|
667 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
668 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
669 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
670 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
671 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
672 |
|
|
673 |
|
|
674 |
|
|
675 |
|
//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
|
676 |
|
// if (page == string.Empty)
|
677 |
|
// page = "test.txt";
|
678 |
|
//
|
679 |
|
// TextReader tr = new StreamReader(page);
|
680 |
|
// string msg = tr.ReadToEnd();
|
681 |
|
|
682 |
|
int rand = new Random().Next(1, 10);
|
683 |
|
string msg = "This is a response from the server :) " + rand;
|
684 |
|
|
685 |
|
Response xmlResp = Response.Randomize();
|
686 |
|
var xml = XmlCommunication.Serialize(xmlResp);
|
687 |
|
//Console.WriteLine(xml);
|
688 |
|
|
689 |
|
msg = xml;
|
690 |
|
|
691 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
692 |
|
|
693 |
|
response.ContentLength64 = buffer.Length;
|
694 |
|
Stream st = response.OutputStream;
|
695 |
|
st.Write(buffer, 0, buffer.Length);
|
696 |
|
|
697 |
|
|
698 |
|
context.Response.Close();
|
699 |
|
}
|
700 |
|
|
701 |
|
else if (context.Request.HttpMethod == "POST") // when client says upload
|
702 |
|
{
|
703 |
|
Console.WriteLine("received POST request");
|
704 |
|
|
705 |
|
string text;
|
706 |
|
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
707 |
|
text = reader.ReadToEnd();
|
708 |
|
Console.WriteLine("Received request:");
|
709 |
|
string requestXML = HttpUtility.UrlDecode(text);
|
710 |
|
Console.WriteLine(requestXML);
|
711 |
|
|
712 |
|
Request newRequest = new Request();
|
713 |
|
Request requestDeserialized = XmlCommunication.Deserialize<Request>(requestXML);
|
714 |
|
|
715 |
|
ClientService newService = new ClientService();
|
716 |
|
newService.UniqueID = GetNextID();
|
717 |
|
newService.ClientRequest = requestDeserialized;
|
718 |
|
// save the request to the queue
|
719 |
|
waitingRequests.Enqueue(newService);
|
720 |
|
|
721 |
|
|
722 |
|
|
723 |
|
// SEND THE ID: - TODO xml format also
|
724 |
|
HttpListenerResponse response = context.Response;
|
725 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
726 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
727 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
728 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
729 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
730 |
|
|
731 |
|
|
732 |
|
|
733 |
|
int rand = new Random().Next(1, 10);
|
734 |
|
string msg = "" + newService.UniqueID;
|
735 |
|
|
736 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
737 |
|
|
738 |
|
response.ContentLength64 = buffer.Length;
|
739 |
|
Stream st = response.OutputStream;
|
740 |
|
st.Write(buffer, 0, buffer.Length);
|
741 |
|
|
742 |
|
|
743 |
|
context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
|
744 |
|
}
|
745 |
|
else
|
746 |
|
{
|
747 |
|
Console.WriteLine("received request other than GET or POST");
|
748 |
|
Console.WriteLine("method: " + context.Request.HttpMethod);
|
749 |
|
Console.WriteLine("headers: " + context.Request.Headers);
|
750 |
|
Console.WriteLine("whole request?: " + context.Request);
|
751 |
|
Console.WriteLine("user: " + context.User);
|
752 |
|
|
753 |
|
|
754 |
|
|
755 |
|
//HttpListenerResponse response = context.Response;
|
756 |
|
//response.AddHeader("Access-Control-Allow-Credentials", "true");
|
757 |
|
//response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
758 |
|
//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
|
759 |
|
//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
760 |
|
//response.AddHeader("Access-Control-Allow-Origin", "*");
|
761 |
|
|
762 |
|
//string msg = "Preflight check? ";
|
763 |
|
|
764 |
|
//byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
765 |
|
|
766 |
|
//response.ContentLength64 = buffer.Length;
|
767 |
|
//Stream st = response.OutputStream;
|
768 |
|
//st.Write(buffer, 0, buffer.Length);
|
769 |
|
|
770 |
|
|
771 |
|
//context.Response.Close(); // ??
|
772 |
|
|
773 |
|
}
|
774 |
|
}
|
775 |
|
}
|
776 |
|
|
777 |
|
|
778 |
|
|
779 |
|
|
780 |
|
|
781 |
|
|
782 |
|
|
783 |
|
|
784 |
|
|
785 |
|
|
786 |
|
|
787 |
|
private void ListenerCallback(IAsyncResult result)
|
788 |
|
{
|
789 |
|
HttpListener listener = (HttpListener)result.AsyncState;
|
790 |
|
// Call EndGetContext to complete the asynchronous operation.
|
791 |
|
HttpListenerContext context = listener.EndGetContext(result);
|
792 |
|
|
793 |
|
Console.WriteLine("callbacking...");
|
794 |
|
|
795 |
|
Thread.Sleep(10000);
|
796 |
|
|
797 |
|
if (context.Request.HttpMethod == "GET") // when client says download
|
798 |
|
{
|
799 |
|
Console.WriteLine("received GET request");
|
800 |
|
|
801 |
|
HttpListenerResponse response = context.Response;
|
802 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
803 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
804 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
805 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
806 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
807 |
|
|
808 |
|
|
809 |
|
|
810 |
|
//string page = Directory.GetCurrentDirectory() + context.Request.Url.LocalPath;
|
811 |
|
// if (page == string.Empty)
|
812 |
|
// page = "test.txt";
|
813 |
|
//
|
814 |
|
// TextReader tr = new StreamReader(page);
|
815 |
|
// string msg = tr.ReadToEnd();
|
816 |
|
|
817 |
|
int rand = new Random().Next(1, 10);
|
818 |
|
string msg = "This is a response from the server :) " + rand;
|
819 |
|
|
820 |
|
Response xmlResp = Response.Randomize();
|
821 |
|
var xml = XmlCommunication.Serialize(xmlResp);
|
822 |
|
//Console.WriteLine(xml);
|
823 |
|
|
824 |
|
msg = xml;
|
825 |
|
|
826 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
827 |
|
|
828 |
|
response.ContentLength64 = buffer.Length;
|
829 |
|
Stream st = response.OutputStream;
|
830 |
|
st.Write(buffer, 0, buffer.Length);
|
831 |
|
|
832 |
|
|
833 |
|
context.Response.Close();
|
834 |
|
}
|
835 |
|
|
836 |
|
else if (context.Request.HttpMethod == "POST") // when client says upload
|
837 |
|
{
|
838 |
|
Console.WriteLine("received POST request");
|
839 |
|
|
840 |
|
string text;
|
841 |
|
using (var reader = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding))
|
842 |
|
text = reader.ReadToEnd();
|
843 |
|
Console.WriteLine("Received request:");
|
844 |
|
Console.WriteLine(HttpUtility.UrlDecode(text));
|
845 |
|
|
846 |
|
|
847 |
|
|
848 |
|
HttpListenerResponse response = context.Response;
|
849 |
|
response.AddHeader("Access-Control-Allow-Credentials", "true");
|
850 |
|
response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
851 |
|
response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time");
|
852 |
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
853 |
|
response.AddHeader("Access-Control-Allow-Origin", "*");
|
854 |
|
|
855 |
|
|
856 |
|
|
857 |
|
int rand = new Random().Next(1, 10);
|
858 |
|
string msg = "OK " + rand;
|
859 |
|
|
860 |
|
byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
861 |
|
|
862 |
|
response.ContentLength64 = buffer.Length;
|
863 |
|
Stream st = response.OutputStream;
|
864 |
|
st.Write(buffer, 0, buffer.Length);
|
865 |
|
|
866 |
|
|
867 |
|
context.Response.Close(); // ?? Works better with this, if this line is absent, the client gets 'stuck' after approximately 6 messages
|
868 |
|
}
|
869 |
|
else
|
870 |
|
{
|
871 |
|
Console.WriteLine("received request other than GET or POST");
|
872 |
|
Console.WriteLine("method: " + context.Request.HttpMethod);
|
873 |
|
Console.WriteLine("headers: " + context.Request.Headers);
|
874 |
|
Console.WriteLine("whole request?: " + context.Request);
|
875 |
|
Console.WriteLine("user: " + context.User);
|
876 |
|
|
877 |
|
|
878 |
|
|
879 |
|
//HttpListenerResponse response = context.Response;
|
880 |
|
//response.AddHeader("Access-Control-Allow-Credentials", "true");
|
881 |
|
//response.AddHeader("Access-Control-Expose-Headers", "ETag");
|
882 |
|
//response.AddHeader("Access-Control-Allow-Headers", "Accept, X-Access-Token, X-Application-Name, X-Request-Sent-Time, Origin, Content-Type, X-Auth-Token");
|
883 |
|
//response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
884 |
|
//response.AddHeader("Access-Control-Allow-Origin", "*");
|
885 |
|
|
886 |
|
//string msg = "Preflight check? ";
|
887 |
|
|
888 |
|
//byte[] buffer = Encoding.UTF8.GetBytes(msg);
|
889 |
|
|
890 |
|
//response.ContentLength64 = buffer.Length;
|
891 |
|
//Stream st = response.OutputStream;
|
892 |
|
//st.Write(buffer, 0, buffer.Length);
|
893 |
|
|
894 |
|
|
895 |
|
//context.Response.Close(); // ??
|
896 |
|
|
897 |
|
}
|
898 |
|
|
899 |
|
|
900 |
|
|
901 |
|
|
902 |
|
|
903 |
|
|
904 |
|
|
905 |
|
|
906 |
|
|
907 |
|
|
908 |
|
//HttpListenerRequest request = context.Request;
|
909 |
|
//// Obtain a response object.
|
910 |
|
//HttpListenerResponse response = context.Response;
|
911 |
|
//// Construct a response.
|
912 |
|
//string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
|
913 |
|
//byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
|
914 |
|
//// Get a response stream and write the response to it.
|
915 |
|
//response.ContentLength64 = buffer.Length;
|
916 |
|
//System.IO.Stream output = response.OutputStream;
|
917 |
|
//output.Write(buffer, 0, buffer.Length);
|
918 |
|
//// You must close the output stream.
|
919 |
|
//output.Close();
|
920 |
|
}
|
921 |
|
|
922 |
|
|
923 |
|
private string GetLocalIPAddress()
|
924 |
|
{
|
925 |
|
var host = Dns.GetHostEntry(Dns.GetHostName());
|
926 |
|
foreach (var ip in host.AddressList)
|
927 |
|
{
|
928 |
|
if (ip.AddressFamily == AddressFamily.InterNetwork)
|
929 |
|
{
|
930 |
|
return ip.ToString();
|
931 |
|
}
|
932 |
|
}
|
933 |
|
throw new Exception("No network adapters with an IPv4 address in the system!");
|
934 |
|
}
|
935 |
|
|
936 |
|
}
|
937 |
|
|
938 |
351 |
}
|
Refactor, cleanup + usage of logging class instead of 'Console.WriteLine's.