From 77832236f70fdd8b73bd01e8fbd4e1d8cd2a9af1 Mon Sep 17 00:00:00 2001 From: fcolin Date: Thu, 1 Feb 2007 09:54:48 +0000 Subject: Utilisateur : Fcolin Date : 30/06/05 Heure : 14:21 Archivé dans $/CSharp/Ivy Commentaire: Bug start time < 0 en l'absence de rejeu a voir ajouter 1s de blank au debut (vss 26) --- CSharp/Ivy/IvyPPC/Ivy.cs | 312 +++++++++++++++++++++++++++++------------------ 1 file changed, 191 insertions(+), 121 deletions(-) (limited to 'CSharp/Ivy') diff --git a/CSharp/Ivy/IvyPPC/Ivy.cs b/CSharp/Ivy/IvyPPC/Ivy.cs index 5119004..5e90a27 100644 --- a/CSharp/Ivy/IvyPPC/Ivy.cs +++ b/CSharp/Ivy/IvyPPC/Ivy.cs @@ -25,7 +25,9 @@ namespace IvyBus public delegate void ClientConnectedHandler (IvyClient app); public delegate void ClientDisconnectedHandler (IvyClient app); public delegate bool DieHandler (IvyClient app, int id ); - + public delegate void ClientAddBindingHandler (IvyClient app, string arg ); + public delegate void ClientRemoveBindingHandler (IvyClient app, string arg ); + public delegate void MessageHandler ( IvyClient app, string[] args ); @@ -42,9 +44,14 @@ namespace IvyBus public event DirectMessageHandler directMessageReceived; /// fires when somebody ask for killing every client on the bus public event DieHandler dieReceived; + /// fires when a client receive a add binding from another client + public event ClientAddBindingHandler addBinding; + /// fires when a client receive a remove binding from another client + public event ClientAddBindingHandler removeBinding; + /// IvyClients accesses the list of the connected clients - public Hashtable IvyClients + public ArrayList IvyClients { get { @@ -65,14 +72,14 @@ namespace IvyBus } /// ClientNames accesses the name list of the connected clients - private String ClientNames + private string ClientNames { get { - String s = appName + " clients are: "; + string s = appName + " clients are: "; lock( clients.SyncRoot ) { - foreach (IvyClient client in clients.Values ) + foreach (IvyClient client in clients ) { s += client.ApplicationName + " "; } @@ -82,7 +89,7 @@ namespace IvyBus } /// AppName the application name - public String AppName + public string AppName { get { @@ -90,10 +97,38 @@ namespace IvyBus } } + public string AppId + { + get + { + return applicationUniqueId; + } + + } + public int AppPriority + { + set + { + applicationPriority = value; + lock ( clients.SyncRoot ) + { + foreach (IvyClient client in clients ) + { + client.sendApplicationId(); + } + } + + } + get + { + return applicationPriority; + } + + } ///SentMessageClasses the first word token of sent messages /// optimise the parsing process when sending messages /// - public String[] SentMessageClasses + public string[] SentMessageClasses { get { @@ -117,28 +152,41 @@ namespace IvyBus } /// the name of the application on the bus - internal String appName; + internal string appName; /// the protocol version number - internal const int PROCOCOLVERSION = 3; + internal const int PROCOCOLVERSION = 4; /// the port for the UDP rendez vous, if none is supplied internal const int DEFAULT_PORT = 2010; + // client default priority + internal const int DEFAULT_PRIORITY = 100; /// the domain for the UDP rendez vous - internal static readonly String DEFAULT_DOMAIN = "127.255.255.255:" + DEFAULT_PORT; - internal const String libVersion = "1.0.0"; + internal static readonly string DEFAULT_DOMAIN = "127.255.255.255:" + DEFAULT_PORT; + internal const string libVersion = "2.0.0"; private bool debug; private static int serial = 0; /* an unique ID for each regexp */ private MyTcpListener app; private ArrayList watchers; private volatile Thread serverThread; // to ensure quick communication of the end - private Hashtable callbacks; - private Hashtable clients_data; - private Hashtable clients; - private String[] sent_messageClasses = null; + + internal enum BindingType { BindRegexp, BindSimple }; + internal struct ApplicationBinding /* Self Applications bindings */ + { + internal BindingType type; + internal Int32 key; + internal MessageHandler callback; + internal string regexp; + internal object[] args; + } + + internal Hashtable bindings; + private ArrayList clients; + private string[] sent_messageClasses = null; private bool stopped = false; internal int applicationPort; /* Application port number */ - internal Hashtable regexp_out; - internal String ready_message = null; + internal string applicationUniqueId; /* identifier Application unique timestamp-ipaddress-port */ + internal int applicationPriority = DEFAULT_PRIORITY; + internal string ready_message = null; // for synchronous event private Control syncControl = null; @@ -154,7 +202,7 @@ namespace IvyBus /// the Ivy agent A performs b.bindMsg("^Hello (*)",cb); /// the Ivy agent B performs b2.sendMsg("Hello world"); /// a thread in A will run the callback cb with its second argument set - /// to a array of String, with one single element, "world" + /// to a array of string, with one single element, "world" /// /// /// the real work begin in the start() method @@ -164,19 +212,20 @@ namespace IvyBus /// /// The hellow message you will send once ready /// - public Ivy(String name, String message) + public Ivy(string name, string message) { - callbacks = Hashtable.Synchronized( new Hashtable() ); - clients = Hashtable.Synchronized( new Hashtable() ); - clients_data = Hashtable.Synchronized( new Hashtable() ); - regexp_out = Hashtable.Synchronized( new Hashtable()); + clients = ArrayList.Synchronized( new ArrayList() ); + //callbacks = Hashtable.Synchronized( new Hashtable() ); + //clients_data = Hashtable.Synchronized( new Hashtable() ); + //regexp_out = Hashtable.Synchronized( new Hashtable()); + bindings = Hashtable.Synchronized( new Hashtable()); appName = name; ready_message = message; - String debug_str = ConfigurationSettings.AppSettings["IVY_DEBUG"]; + string debug_str = ConfigurationSettings.AppSettings["IVY_DEBUG"]; if ( debug_str != null ) debug = bool.Parse(debug_str); } - public Ivy(String name, String message, Control sync) :this( name, message ) + public Ivy(string name, string message, Control sync) :this( name, message ) { syncControl = sync; } @@ -196,7 +245,7 @@ namespace IvyBus /// * /// /// - public void start(String domainbus) + public void start(string domainbus) { if (domainbus == null) domainbus = Environment.GetEnvironmentVariable("IVYBUS"); @@ -204,9 +253,14 @@ namespace IvyBus domainbus = DEFAULT_DOMAIN; try { + IPAddress localaddr = Dns.Resolve(Dns.GetHostName()).AddressList[0]; app = new MyTcpListener(IPAddress.Any,0); app.Start(); applicationPort = ((IPEndPoint) app.LocalEndpoint).Port; + applicationUniqueId = string.Format("{0}-{1}-{2}", + DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond, + localaddr.ToString().Replace(".",""), + applicationPort ); } catch (IOException e) { @@ -228,7 +282,7 @@ namespace IvyBus // Wait for readyness while ( serverThread.ThreadState != ThreadState.Running || !app.IsActive()) { - Console.WriteLine( " Ivy Threading start in progress..." ); + traceDebug( " Ivy Threading start in progress..." ); Thread.Sleep( 100 ); } // sends the broadcasts and listen to incoming connexions @@ -237,11 +291,18 @@ namespace IvyBus ((IvyWatcher) watchers[i]).start(); } } + public void SortClients() + { + lock ( clients.SyncRoot ) + { + clients.Sort(new IvyClient.IvyClientPriority()); + } + } /* a small private method for debbugging purposes */ - public String domains(String toparse) + public string domains(string toparse) { - String s = "broadcasting on "; + string s = "broadcasting on "; Ivy.Domain[] d = parseDomains(toparse); for (int index = 0; index < d.Length; index++) { @@ -250,9 +311,9 @@ namespace IvyBus return s; } - internal Domain[] parseDomains(String domainbus) + internal Domain[] parseDomains(string domainbus) { - String[] st = domainbus.Split(','); + string[] st = domainbus.Split(','); Domain[] d = new Domain[st.Length]; for (int i = 0; i < st.Length; i++) { @@ -297,7 +358,7 @@ namespace IvyBus copyClient = new IvyClient[clients.Count]; lock( clients.SyncRoot ) { - clients.Values.CopyTo( copyClient,0 ); + clients.CopyTo( copyClient,0 ); } foreach (IvyClient client in copyClient ) { @@ -329,14 +390,14 @@ namespace IvyBus /// the number of messages actually sent /// /// - public int sendMsg(String message) + public int sendMsg(string message) { int count = 0; // an alternate implementation would one sender thread per client // instead of one for all the clients. It might be a performance issue lock ( clients.SyncRoot ) { - foreach (IvyClient client in clients.Values ) + foreach (IvyClient client in clients ) { count += client.sendMsg(message); } @@ -395,27 +456,31 @@ namespace IvyBus /// the id of the regular expression /// /// + // + // for compatibility raison with old IVY public int bindMsg(String regexp, MessageHandler callback) { return bindMsg( regexp, callback, null); } - public int bindMsg(String regexp, MessageHandler callback, object data) + public int bindMsg(string regexp, MessageHandler callback, params object[] args ) { // creates a new binding (regexp,callback) - Int32 key = serial++; - // TODO Make a unique Object grouping - lock (regexp_out.SyncRoot) regexp_out.Add( key, regexp); - lock (callbacks.SyncRoot) callbacks.Add( key, callback); - lock (clients_data.SyncRoot) clients_data.Add( key, data); + ApplicationBinding newbind; + newbind.type = BindingType.BindRegexp; + newbind.key = serial++; + newbind.regexp = regexp; + newbind.callback = callback; + newbind.args = args; + lock (bindings.SyncRoot) bindings.Add( newbind.key, newbind); // notifies the other clients this new regexp lock ( clients.SyncRoot ) { - foreach (IvyClient c in clients.Values ) + foreach (IvyClient c in clients ) { - c.sendRegexp(key, regexp); + c.sendBinding(newbind); } } - return key; + return newbind.key; } /// unsubscribes a regular expression @@ -425,17 +490,19 @@ namespace IvyBus /// public void unBindMsg(int id) { - if ((regexp_out[id] == null) || (callbacks[id] == null)) + if ( ! bindings.ContainsKey( id ) ) { throw new IvyException("client wants to remove an unexistant regexp " + id); } + ApplicationBinding bind = (ApplicationBinding) bindings[id]; lock( clients.SyncRoot ) { - foreach (IvyClient c in clients.Values ) + foreach (IvyClient c in clients ) { - c.delRegexp(id); + c.delBinding(bind); } } + lock( bindings.SyncRoot ) bindings.Remove( id ); } /// unsubscribes a regular expression @@ -446,15 +513,15 @@ namespace IvyBus /// the string for the regular expression /// /// - public bool unBindMsg(String re) + public bool unBindMsg(string re) { - foreach (Int32 k in regexp_out.Keys ) + foreach (ApplicationBinding bind in bindings.Values ) { - if (((String) regexp_out[k]).CompareTo(re) == 0) + if ( bind.regexp == re ) { try { - unBindMsg(k); + unBindMsg(bind.key); } catch (IvyException ie) { @@ -465,6 +532,45 @@ namespace IvyBus } return false; } + + + /// Subscribes to a simple expression ( msg ar1 arg2 arg3 etc). + /// + /// + /// The callback will be executed with + /// the saved parameters of the regexp as arguments when a message will sent + /// by another agent. A program doesn't receive its own messages. + /// + /// + /// a regular expression, groups are done with parenthesis + /// + /// any objects implementing the Ivy.MessageListener + /// + /// the id of the regular expression + /// + /// + + public int bindSimpleMsg(string expression, MessageHandler callback, params object[] args ) + { + // creates a new binding (regexp,callback) + ApplicationBinding newbind; + newbind.type = BindingType.BindSimple; + newbind.key = serial++; + newbind.regexp = expression; + newbind.callback = callback; + newbind.args = args; + lock (bindings.SyncRoot) bindings.Add( newbind.key, newbind); + // notifies the other clients this new regexp + lock ( clients.SyncRoot ) + { + foreach (IvyClient c in clients ) + { + c.sendBinding(newbind); + } + } + return newbind.key; + } + internal void FireDirectMessage (IvyClient app, int id, string arg ) { if ( directMessageReceived != null ) @@ -492,6 +598,24 @@ namespace IvyBus else clientDisconnected( app); } } + internal void FireClientAddBinding (IvyClient app, string regexp) + { + if ( addBinding != null ) + { + if ( syncControl != null ) + syncControl.Invoke( addBinding, new object[]{app,regexp}); + else addBinding( app,regexp); + } + } + internal void FireClientRemoveBinding (IvyClient app, string regexp) + { + if ( removeBinding != null ) + { + if ( syncControl != null ) + syncControl.Invoke( removeBinding, new object[]{app,regexp}); + else removeBinding( app,regexp); + } + } internal bool FireDie (IvyClient app, int id ) { if ( dieReceived != null ) @@ -511,7 +635,7 @@ namespace IvyBus { lock( clients.SyncRoot ) { - clients.Remove(c.ClientKey); + clients.Remove(c); } } @@ -520,10 +644,10 @@ namespace IvyBus /// /// The name of the Ivy agent you're looking for /// - public ArrayList getIvyClientsByName(String name) + public ArrayList getIvyClientsByName(string name) { ArrayList v = new ArrayList(); - foreach (IvyClient ic in clients.Values ) + foreach (IvyClient ic in clients ) { if (((ic.ApplicationName).CompareTo(name)) == 0) v.Add(ic); @@ -544,53 +668,25 @@ namespace IvyBus IvyClient client = new IvyClient(this,socket); lock ( clients.SyncRoot ) { - clients.Add( client.ClientKey, client); + clients.Add(client); } traceDebug(ClientNames); } - internal void callCallback(IvyClient client, Int32 key, String[] tab) + internal void callCallback(IvyClient client, Int32 key, string[] tab) { - MessageHandler callback = (MessageHandler) callbacks[key]; - object data = clients_data[key]; - if (callback == null) + ApplicationBinding bind = ( ApplicationBinding ) bindings[key]; + if (bind.callback == null) { throw new IvyException("(callCallback) Not regexp matching id " + key); } if ( syncControl != null ) - syncControl.Invoke( callback, new object[]{client,tab}); - else callback(client, tab); + syncControl.Invoke( bind.callback, new object[]{client,tab}); + else bind.callback(client, tab); } - private static String[] myTokenize(String s, String separator) - { - int index = 0, last = 0, length = s.Length; - ArrayList v = new ArrayList(); - if (length != 0) - while (true) - { - index = s.IndexOf(separator, last); - if (index == - 1) - { - v.Add(s.Substring(last, (length) - (last))); - break; - } - else if (index < s.Length) - { - v.Add(s.Substring(last, (index) - (last))); - last = index + 1; - } - else - { - break; - } - } - String[] tab = new String[v.Count]; - v.CopyTo(tab); - return tab; - } - public static String getDomain(String domainbus) + public static string getDomain(string domainbus) { if (domainbus == null) { @@ -607,7 +703,7 @@ namespace IvyBus /// checks the "validity" of a regular expression. - internal bool CheckRegexp(String exp) + internal bool CheckRegexp(string exp) { bool regexp_ok = true; // TODO Bug @@ -639,7 +735,7 @@ namespace IvyBus return false; lock( clients.SyncRoot ) { - foreach (IvyClient client in clients.Values ) + foreach (IvyClient client in clients ) { if (clnt != client && client.sameClient(clnt)) return true; @@ -682,7 +778,7 @@ namespace IvyBus } - private void traceDebug(String s) + private void traceDebug(string s) { if (debug) Console.Out.WriteLine("-->ivy<-- " + s); @@ -690,7 +786,7 @@ namespace IvyBus internal class Domain { - public virtual String Domainaddr + public virtual string Domainaddr { get { @@ -706,43 +802,17 @@ namespace IvyBus } } - private String domainaddr; + private string domainaddr; private int port; - public Domain( String domainaddr, int port) + public Domain( string domainaddr, int port) { this.domainaddr = domainaddr; this.port = port; } - public override String ToString() + public override string ToString() { return domainaddr + ":" + port; } } - - /* - * unitary test. Normally, running Ivy.Ivy should stop in 2.3 seconds :) - */ - [STAThread] - public static void Main(String[] args) - { - Ivy bus = new Ivy("Test Unitaire", "TU ready"); - try - { - bus.start(null); - try - { - Thread.Sleep(new TimeSpan(10000 * 2000)); - } - catch (ThreadInterruptedException ie) - { - } - bus.stop(); - } - catch (IvyException ie) - { - Console.Error.WriteLine( ie.Message ); - Console.Error.WriteLine( ie.StackTrace ); - } - } } } \ No newline at end of file -- cgit v1.1