examples/reference/csharp/net/src/net_io.cs

270 lines
8.1 KiB
C#

/*
* Efl.Net input/output examples.
*
* This example builds on the core_io example by connecting to a remote server
* using a dialer and a command queue. The response is printed to stdout.
*/
using System;
public class ExampleRunner
{
private eina.List<efl.io.Copier> waiting = null;
private eina.List<string> commands = null;
private eina.Slice delimiter;
private efl.net.dialer.Tcp dialer = null;
private efl.io.Copier sender = null;
private efl.io.Copier receiver = null;
public void Run()
{
efl.ui.Config.Run();
}
// call this method to cleanly shut down our example
public void Quit()
{
if (waiting != null)
{
Console.Error.WriteLine("ERROR: {0} operations were waiting!", waiting.Length);
waiting.Dispose();
waiting = null;
}
if (receiver != null)
{
receiver.Close();
receiver.GetDestination().Dispose();
receiver.Dispose();
receiver = null;
}
if (sender)
{
sender.Close();
sender.GetSource().Dispose();
source.Dispose();
}
if (dialer)
dialer.Dispose();
// efl_exit(retval); // TODO missing
efl.ui.Config.Exit();
}
// iterate through the commands to send through the dialler
public void CommandNext()
{
efl.io.Reader send_queue = sender.GetSource();
if (commands != null)
{
send_queue.EosMark();
return;
}
string cmd = commands[0];
// commands.RemoveAt(0); // TODO missing
eina.Slice slice;
// slice = (Eina_Slice)EINA_SLICE_STR(cmd); // TODO missing
send_queue.Write(slice, null);
// Console.WriteLine("INFO: sent '{0}'", EINA_SLICE_STR_PRINT(slice)); // TODO missing
// don't use delimiter directly, 'Len' may be changed!
slice = delimiter;
send_queue.Write(slice, null);
}
void ReceiverData(efl.io.Queue sender, EventArgs e)
{
eina.Slice slice = sender.GetSlice();
// Can be caused when we issue efl.io.Queue.Clear()
if (slice.Len == 0) return;
// If the server didn't send us the line terminator and closed the
// connection (ie: efl_io_reader_eos_get() == true) or if the buffer
// limit was reached then we may have a line without a trailing delimiter.
// if (slice.EndsWith(delimiter)) // TODO missing
// slice.Len -= delimiter.Len;
// Console.WriteLine("INFO: received '{0}'", EINA_SLICE_STR_PRINT(slice)); // TODO missing
sender.Clear();
CommandNext();
}
void DialerConnected(efl.net.dialer.Tcp sender, EventArgs e)
{
Console.WriteLine("INFO: connected to {0} ({1})", sender.GetAddressDial(), sender.GetAddressRemote());
CommandNext();
}
void CopierDone(efl.io.Copier sender, EventArgs e)
{
Console.WriteLine("INFO: {0} done", sender.GetName());
// waiting.Remove(sender); // TODO missing
if (waiting.Empty())
Quit(EXIT_SUCCESS);
}
void CopierError(efl.io.Copier sender, eina.Error perr)
{
Console.Error.WriteLine(stderr, "INFO: {0} error: #{1} '{2}'", sender.GetName(), perr, perr.Message);
Quit(EXIT_FAILURE);
}
private static void SetCopierCbs(efl.io.Copier copier)
{
copier.DONE += CopierDone;
copier.ERROR += CopierError;
}
public ExampleRunner()
{
string address = "example.com:80";
ulong buffer_limit = 128;
efl.io.Queue send_queue, receive_queue;
commands = new eina.List<string>();
commands.Append("HEAD / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n");
// delimiter = (Eina_Slice)EINA_SLICE_STR("\r\n"); // TODO missing
// Without a send_queue we'd have to manually implement an
// efl.io.Reader object that would provide partial data when
// efl.io.Reader.read() is called by efl.io.Copier. This is
// cumbersome... we just want to write a full command and have the
// queue to handle that for us.
//
// Our example's usage is to write each command at once followed by
// the line delimiter, then wait for a reply from the server, then
// write another.
try
{
send_queue = new efl.io.QueueConcrete(null, (efl.io.Queue equeue) => {
equeue.SetName("send_queue");
equeue.SetLimit(buffer_limit);
});
}
catch
{
Console.Error.WriteLine("ERROR: could not create efl.io.Queue (send)");
Quit(EXIT_FAILURE);
throw;
}
// Without a receive_queue we'd have to manually implement an
// efl.io.Writer object that would handle write of partial data
// with efl.io.Writer.write() is called by efl.io.Copier.
//
// For output we could have another solution as well: use null
// destination and handle "line" or "data" events manually,
// stealing the buffer so it doesn't grow.
//
// Our example's usage is to peek its data with GetSlice() then
// Clear().
try
{
receive_queue = new efl.io.QueueConcrete(null, (efl.io.Queue equeue) => {
equeue.SetName("receive_queue");
equeue.SetLimit(buffer_limit);
});
receive_queue.SLICE_CHANGED += ReceiverData;
}
catch
{
Console.Error.WriteLine("ERROR: could not create efl.io.Queue (receive)");
Quit(EXIT_FAILURE);
throw;
}
// some objects such as the Efl.Io.Copier and Efl.Net.Dialer.Tcp
// depend on main loop, thus their parent must be a loop
// provider. We use the loop passed to our main method.
// efl.Loop loop = ev->object; // TODO missing
// The TCP client to use to send/receive network data
try
{
dialer = new efl.net.dialer.TcpConcrete(loop, (efl.net.dialer.Tcp edialer) => {
edialer.SetName("dialer");
});
dialer.CONNECTED += DialerConnected;
}
catch
{
Console.Error.WriteLine("ERROR: could not create efl.net.dialer.Tcp");
Quit(EXIT_FAILURE);
throw;
}
// sender: send_queue->network
try
{
sender = new efl.io.CopierConcrete(loop, (efl.io.Copier esender) => {
esender.SetName("sender");
esender.SetLineDelimiter(delimiter);
esender.SetSource(send_queue);
esender.SetDestination(dialer);
});
SetCopierCbs(sender);
}
catch
{
Console.Error.WriteLine("ERROR: could not create efl.io.Copier (sender)");
Quit(EXIT_FAILURE);
throw;
}
// receiver: network->receive_queue
try
{
receiver = new efl.io.CopierConcrete(loop, (efl.io.Copier ereceiver) => {
ereceiver.SetName("receiver");
ereceiver.SetLineDelimiter(delimiter);
ereceiver.SetSource(dialer);
ereceiver.SetDestination(send_queue);
});
SetCopierCbs(receiver);
}
catch
{
Console.Error.WriteLine("ERROR: could not create Efl_Io_Copier (receiver)");
Quit(EXIT_FAILURE);
throw;
}
eina.Error err = dialer.Dial(address);
if (err != eina.Error.NO_ERROR)
{
var msg = $"ERROR: could not dial {address}: {err.Message}";
Console.Error.WriteLine(msg);
Quit(EXIT_FAILURE);
throw new SEHException(msg);
}
waiting.Append(sender);
waiting.Append(receiver);
}
}
public static class Example
{
public static void Main()
{
efl.All.Init(efl.Components.Basic);
var exr = new ExampleRunner();
exr.Run();
efl.All.Shutdown();
}
}