/// François-Régis Colin
/// http://www.tls.cena.fr/products/ivy/
/// *
/// (C) CENA
/// *
namespace IvyProbeConsole
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Text.RegularExpressions;
using System.IO;
using System.Configuration;
using System.Diagnostics;
using IvyBus;
using Gnu;
/// Console implementation of the ivyprobe test program.
///
/// Mainly used for testing and debugging purpose
public class IvyProbeConsole
{
public virtual bool ExitOnDie
{
set
{
exitOnDie = value;
}
}
public void BindFromFile(string name)
{
string line;
try
{
FileStream file = new FileStream(name, FileMode.Open, FileAccess.Read);
TextReader reader = new StreamReader(file);
while ((line = reader.ReadLine()) != null)
{
bus.BindMsg(line, receive);
}
}
catch (FileNotFoundException e)
{
Console.WriteLine(e.Message);
}
}
public const string helpCommands =
"Available commands:\n"+
".die CLIENTNAME sends a die message\n" +
".direct CLIENTNAME ID MESSAGE sends the direct message to the client, with a message id set to the numerical ID\n" +
".bye quits the application\n" +
".quit idem\n" +
".list lists the available clients\n" +
".ping sends a ping request if IVY_PING is enabled\n" +
".bind REGEXP binds to a regexp at runtime\n" +
".unbind REGEXP unbinds to a regexp at runtime";
public const String helpmsg =
"usage: IvyProbe [options] [regexp]\n" +
"\t-b BUS\tspecifies the Ivy bus domain\n" +
"\t-n ivyname (default JPROBE)\n" +
"\t-q\tquiet, no tty output\n" +
"\t-d\tdebug\n" +
"\t-t\ttime stamp each message\n" +
"\t-h\thelp\n\n" +
"\t regexp is a Perl5 compatible regular expression";
private TextReader in_Renamed;
private volatile Thread looperThread;
private Ivy bus;
private bool timestamp, quiet, debug, exitOnDie = false;
enum Command {
direct,
die,
unbind,
bind,
ping,
quit,
bye,
list,
help};
const string reg_parse =
@"^\.(?direct) (?[^ ]*) (?[0-9]+) (?.*)$|" +
@"^\.(?die) (?.*)$|" +
@"^\.(?unbind) (?.*)$|" +
@"^\.(?bind) (?.*)$|" +
@"^\.(?ping) (?.*)$|" +
@"^\.(?quit)$|" +
@"^\.(?bye)$|" +
@"^\.(?list)$|" +
@"^\.(?help)$|";
private Regex cmd_regexp;
[STAThread]
public static void Main(String[] args)
{
string name = "C#PROBE";
string fname = null;
bool quiet = false;
bool timestamp = false;
string domain = Ivy.GetDomain(null);
bool debug = false;
domain = Properties.Settings.Default.domain;
name = Properties.Settings.Default.name;
quiet = Properties.Settings.Default.quiet;
timestamp = Properties.Settings.Default.timestamp;
debug = Properties.Settings.Default.IvyDebug;
GetOpt opt = new GetOpt(args, "f:n:b:dqht");
Arg a;
while ((a = opt.NextArg()) != null)
{
switch (a.Flag)
{
case 'd':
debug = true;
break;
case 'b':
domain = a.Parameter;
break;
case 'n':
name = a.Parameter;
break;
case 'f':
fname = a.Parameter;
break;
case 'q':
quiet = true;
break;
case 't':
timestamp = true;
break;
case 'h': default:
System.Console.Out.WriteLine(helpmsg);
System.Environment.Exit(0);
break;
}
}
IvyProbeConsole p = new IvyProbeConsole(System.Console.In, timestamp, quiet, debug );
p.ExitOnDie = true;
Ivy bus = new Ivy(name, name + " ready");
p.start(bus);
if (fname != null)
p.BindFromFile(fname);
foreach(string ex in opt.Extras)
{
if (!quiet)
System.Console.Out.WriteLine("you want to subscribe to " + ex);
bus.BindMsg(ex, p.receive);
}
if (!quiet)
System.Console.Out.WriteLine(Ivy.Domains(domain));
bus.Start(domain);
}
public IvyProbeConsole(TextReader in_Renamed, bool timestamp, bool quiet, bool debug)
{
this.in_Renamed = in_Renamed;
this.timestamp = timestamp;
this.quiet = quiet;
this.debug = debug;
try
{
cmd_regexp = new Regex(reg_parse, RegexOptions.IgnoreCase);
}
catch (ArgumentException ree)
{
System.Console.Error.WriteLine("Regexp fatal error in the Probe program.");
System.Console.Error.WriteLine(ree.StackTrace);
System.Environment.Exit(0);
}
}
public virtual void start(Ivy bus)
{
if (looperThread != null)
throw new IvyException("Probe already started");
this.bus = bus;
bus.ClientConnected += connect;
bus.ClientDisconnected += disconnect;
bus.DieReceived += die ;
bus.DirectMessageReceived += directMessage;
bus.BindingAdd += new EventHandler(bus_BindingAdd);
bus.BindingRemove += new EventHandler(bus_BindingRemove);
bus.BindingFilter += new EventHandler(bus_BindingFilter);
looperThread = new Thread(new ThreadStart(Run));
looperThread.Name = "Keyboard Input Thread";
looperThread.Start();
}
void bus_BindingFilter(object sender, IvyEventArgs e)
{
println("filtred regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
}
void bus_BindingRemove(object sender, IvyEventArgs e)
{
println("Removed regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
}
void bus_BindingAdd(object sender, IvyEventArgs e)
{
println("Added regexp {0} from {1}", e.Argument, e.Client.ApplicationName);
}
public void Run()
{
traceDebug("Thread started");
Thread thisThread = Thread.CurrentThread;
String s;
// "infinite" loop on keyboard input
while (looperThread == thisThread)
{
s = in_Renamed.ReadLine();
if (s == null)
break;
if (s.Length == 0) continue;
if ( s.StartsWith( ".") )
parseCommand(s);
else
{
println("-> Sent to " + bus.SendMsg(s) + " peers");
}
}
println("End of input. Good bye !");
bus.Stop();
traceDebug("Probe Thread stopped");
}
internal void parseCommand(string s)
{
Match result;
traceDebug("parsing the [" + s + "] (length " + s.Length + ") string");
result = cmd_regexp.Match(s);
if (result.Success)
{
string cmd = result.Groups["cmd"].Value;
string target;
try
{
Command TheCommand = (Command)Enum.Parse(typeof(Command), cmd);
switch ( TheCommand )
{
case Command.direct:
{
target = result.Groups["target"].Value;
ushort id = ushort.Parse(result.Groups["id"].Value);
string message = result.Groups["message"].Value;
List v = bus.GetClientsByName(target);
if (v.Count == 0)
println("no Ivy client with the name \"" + target + "\"");
for (int i = 0; i < v.Count; i++)
v[i].SendDirectMsg(id, message);
}
break;
case Command.die:
target = result.Groups["target"].Value;
if (bus.Die(target, ".die command") == 0)
println("no Ivy client with the name \"" + target + "\"");
break;
case Command.unbind:
target = result.Groups["target"].Value;
if (bus.UnbindMsg(target))
println("you want to unsubscribe to " + target);
else
println("you can't unsubscribe to " + target + ", your're not subscribed to it");
break;
case Command.bind:
target = result.Groups["target"].Value;
println("you want to subscribe to " + target);
bus.BindMsg(target, receive);
break;
case Command.ping:
target = result.Groups["target"].Value;
if (bus.Ping(target, "test") == 0)
println("no Ivy client with the name \"" + target + "\"");
break;
case Command.quit:
case Command.bye:
bus.Stop();
System.Environment.Exit(0);
break;
case Command.list:
println(bus.IvyClients.Count + " clients on the bus");
foreach (IvyClient client in bus.IvyClients )
println("-> " + client.ApplicationName);
break;
case Command.help:
println(helpCommands);
break;
}
}
catch (ArgumentException)
{
Console.WriteLine("manque de la commande dans l'enum");
}
}
}
// parseCommand
private void connect(object sender, IvyEventArgs e)
{
println(e.Client.ApplicationName + " connected from "+e.Client.RemoteAddress+":"+e.Client.RemotePort);
}
private void disconnect(object sender, IvyEventArgs e)
{
println(e.Client.ApplicationName + " disconnected ");
}
private void die(object sender, IvyDieEventArgs e)
{
println("received die msg from " + e.Client.ApplicationName + " good bye cause: "+e.Argument);
/* I cannot stop the readLine(), because it is native code */
if (exitOnDie)
System.Environment.Exit(0);
}
private void directMessage(object sender, IvyEventArgs e)
{
println(e.Client.ApplicationName + " direct Message " + e.Id + e.Argument);
}
private void receive(object sender, IvyMessageEventArgs e)
{
String s = e.Client.ApplicationName + " sent ";
s += string.Join(",", e.Arguments);
println(s);
}
[Conditional("DEBUG")]
private void traceDebug(String s)
{
Trace.WriteLineIf(debug, "-->Probe<-- " + s);
}
private void println(string format, params object[] args)
{
if (!quiet)
{
if (timestamp) System.Console.Out.Write(string.Format("[ {0|HH:mm:ss.fff} ]",System.DateTime.Now ));
System.Console.Out.WriteLine(string.Format(format,args));
}
}
}
}