/// 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; using System.Collections.ObjectModel; /// 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("broadcasting on " + Ivy.GetDomain(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; ReadOnlyCollection 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.GetArguments()); 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)); } } } }