Reputation: 277
I have a small web server class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
namespace Automatic_Record
{
class WebServer
{
private readonly HttpListener _listener = new HttpListener();
private readonly Func<HttpListenerRequest, Task<string>> _responderMethod;
public WebServer(string[] prefixes, Func<HttpListenerRequest, Task<string>> method)
{
if (!HttpListener.IsSupported)
throw new NotSupportedException(
"Needs Windows XP SP2, Server 2003 or later.");
// URI prefixes are required, for example
// "http://localhost:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// A responder method is required
if (method == null)
throw new ArgumentException("method");
foreach (string s in prefixes)
_listener.Prefixes.Add(s);
_responderMethod = method;
_listener.Start();
}
public WebServer(Func<HttpListenerRequest, Task<string>> method, params string[] prefixes)
: this(prefixes, method) { }
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
ThreadPool.QueueUserWorkItem(async (c) =>
{
var ctx = c as HttpListenerContext;
try
{
string rstr = await _responderMethod(ctx.Request);
System.Diagnostics.Trace.Write(ctx.Request.QueryString);
//ctx.Request.QueryString
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}, _listener.GetContext());
}
}
catch { } // suppress any exceptions
});
}
public void Stop()
{
_listener.Stop();
_listener.Close();
}
}
}
I'm making instance of the web server in form1 constructor:
var ws = new WebServer(
request => Task.Run(() => SendResponseAsync(request)),
"http://+:8098/");
ws.Run();
The i have the SendResponseAsync method:
public async Task<string> SendResponseAsync(HttpListenerRequest request)
{
string result = "";
string key = request.QueryString.GetKey(0);
if (key == "cmd")
{
if (request.QueryString[0] == "unmute")
{
ChangeProcessAudioVolume.test(100););
return "unmute";
}
if (request.QueryString[0] == "mute")
{
ChangeProcessAudioVolume.test(0);
return "mute";
}
if (request.QueryString[0] == "uploadstatus")
{
switch (Youtube_Uploader.uploadstatus)
{
case "uploading file":
return "uploading " + Youtube_Uploader.fileuploadpercentages;
case "status":
return Youtube_Uploader.fileuploadpercentages.ToString();
case "file uploaded successfully":
Youtube_Uploader.uploadstatus = "";
return "upload completed," + Youtube_Uploader.fileuploadpercentages + ","
+ Youtube_Uploader.time;
default:
return "upload unknown state";
}
}
if (request.QueryString[0] == "nothing")
{
return "Connection Success";
}
if (request.QueryString[0] == "start")
{
StartRecrod();
return "Recording started";
}
if (request.QueryString[0] == "stop")
{
dirchanged = false;
StartRecrod();
string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);
uploadedFilesList.Add(fileforupload);
Youtube_Uploader youtubeupload = new Youtube_Uploader(fileforupload);
}
else
{
result = "Nothing have been done";
}
return result;
}
Then the WatchDirectory method:
private async Task<string> WatchDirectory()
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
watcher.Path = userVideosDirectory;
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
watcher.Filter = "*.mp4";
watcher.Changed += (sender, e) =>
{
if (e.ChangeType == WatcherChangeTypes.Changed)
{
var info = new FileInfo(e.FullPath);
var theSize = info.Length;
label5.BeginInvoke((Action)(() =>
{
label5.Text = theSize.ToString();
}));
}
tcs.SetResult(e.FullPath);
};
watcher.EnableRaisingEvents = true;
return await tcs.Task;
}
}
And the WaitForUnlockedFile:
private async Task WaitForUnlockedFile(string fileName)
{
while (true)
{
try
{
using (IDisposable stream = File.Open(fileName, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.None))
{ /* on success, immediately dispose object */ }
break;
}
catch (IOException)
{
}
await Task.Delay(100);
}
}
What it does is getting a command from the client in java using android-studio and then return a string. For example if the command is "upload file" then it return the string "uploading" and the percentages.
Now my problem is that i want while it's doing await waiting for the file to be created using the WatchDirectory to report to the client the java side.
When the command is "stop"
if (request.QueryString[0] == "stop")
Then it's doing the await :
string fileforupload = await WatchDirectory();
await WaitForUnlockedFile(fileforupload);
Somehow here or maybe in the WatchDirectory i want to report to the client to the java side to send it a string saying something like "creating file" until it's finisihing the WatchDirectory process and then to send it a string like "file created".
I know here in the c# that it's taking time when it's making the WatchDirectory and creating the file it might take a second or maybe 30 seconds and i want in this time to report to send a string "creating file" and then "file created".
The problem is where to do it ? And how to do it since i can't just make something like return "creating file" ?
Upvotes: 0
Views: 78
Reputation: 456927
async
does not change the HTTP protocol. If you want to send multiple responses, then you'll have to rely on the client to send multiple requests. You'll have to keep track of each "in-flight" operation in addition to all the requests, and invent some way of associating requests with the operations (e.g., a GUID).
In short, you'll have to use AJAX or some similar mechanism.
Upvotes: 1