diff options
Diffstat (limited to 'CSharp/Ivy/IvyPPC/Ivy.cs')
-rw-r--r-- | CSharp/Ivy/IvyPPC/Ivy.cs | 312 |
1 files changed, 191 insertions, 121 deletions
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;
/// <summary>fires when somebody ask for killing every client on the bus</summary>
public event DieHandler dieReceived;
+ /// <summary>fires when a client receive a add binding from another client</summary>
+ public event ClientAddBindingHandler addBinding;
+ /// <summary>fires when a client receive a remove binding from another client</summary>
+ public event ClientAddBindingHandler removeBinding;
+
/// <summary>IvyClients accesses the list of the connected clients</summary>
- public Hashtable IvyClients
+ public ArrayList IvyClients
{
get
{
@@ -65,14 +72,14 @@ namespace IvyBus }
/// <summary>ClientNames accesses the name list of the connected clients</summary>
- 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 }
/// <summary>AppName the application name</summary>
- 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;
+ }
+
+ }
///<summary>SentMessageClasses the first word token of sent messages
///<remarks> optimise the parsing process when sending messages </remarks>
///</summary>
- 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 <c>b.bindMsg("^Hello (*)",cb);</c>
/// the Ivy agent B performs <c>b2.sendMsg("Hello world");</c>
/// 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"
/// </example>
/// <remarks>
/// the real work begin in the start() method
@@ -164,19 +212,20 @@ namespace IvyBus /// </param>
/// <param name='message'>The hellow message you will send once ready
/// </param>
- 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 /// *
///
/// </param>
- 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 /// <returns>the number of messages actually sent
///
/// </returns>
- 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 /// <returns>the id of the regular expression
///
/// </returns>
+ //
+ // 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;
}
/// <summary> unsubscribes a regular expression
@@ -425,17 +490,19 @@ namespace IvyBus /// </param>
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 );
}
/// <summary> unsubscribes a regular expression
@@ -446,15 +513,15 @@ namespace IvyBus /// <param name='re'>the string for the regular expression
///
/// </param>
- 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;
}
+
+
+ /// <summary> Subscribes to a simple expression ( msg ar1 arg2 arg3 etc).
+ /// </summary>
+ /// <remarks>
+ /// 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.
+ /// </remarks>
+ ///
+ /// <param name='regexp'>a regular expression, groups are done with parenthesis
+ /// </param>
+ /// <param name='callback'>any objects implementing the Ivy.MessageListener
+ /// </param>
+ /// <returns>the id of the regular expression
+ ///
+ /// </returns>
+
+ 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 /// </summary>
/// <param name='name'>The name of the Ivy agent you're looking for
/// </param>
- 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 |