/// <summary>
 /// Sets the answer object
 /// </summary>
 /// <param name="answer"></param>
 public void setAnswerObject(IICCCMessage answer)
 {
 }
 /// <summary>
 /// Sets the answer object.
 /// </summary>
 /// <param name="answer"></param>
 public void setAnswerObject(IICCCMessage answer)
 {
     this.answer = answer;
 }
Example #3
0
        private bool sendRegistration(IICCCMessage message)
        {
            // Precheck the local endpoint:
            if(this.localEndpoint == string.Empty)
            {
                this.earlyMessages.Enqueue(message);
                return false;
            }

            // Check the local endpoint inside the message:
            var registrationMessage = message as ICCCRegisterListener;
            if(registrationMessage.IPAddressPort == string.Empty)
            {
                registrationMessage.IPAddressPort = this.localEndpoint;
            }

            // Send the message now:
            var ok = false;
            for(var tries = 0; tries < 10; tries++)
            {
                var answer = ICCCConnection.INSTANCE.send2Any(message, ICCCKind.KindOcean) as ICCCDefaultAnswer;
                if(answer == null || !answer.CommandSuccessful)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(10));
                    continue;
                }
                else
                {
                    ok = true;
                    break;
                }
            }

            // Was not possible? Store it for later:
            if(!ok)
            {
                this.earlyMessages.Enqueue(message);
                return false;
            }

            return true;
        }
 /// <summary>
 /// Sets the answer object.
 /// </summary>
 /// <param name="answer">The new answer object</param>
 public void setAnswerObject(IICCCMessage answer)
 {
     this.answerPrototype = answer;
 }
Example #5
0
        private bool sendDeregistration(IICCCMessage message)
        {
            // Precheck the local endpoint:
            if(this.localEndpoint == string.Empty)
            {
                return false;
            }

            // Check the local endpoint inside the message:
            var deregistrationMessage = message as ICCCListenerUpdate;
            if(deregistrationMessage.IPAddressPort == string.Empty)
            {
                deregistrationMessage.IPAddressPort = this.localEndpoint;
            }

            // Send the message now:
            var ok = false;
            for(var tries = 0; tries < 10; tries++)
            {
                var answer = ICCCConnection.INSTANCE.send2Any(message, ICCCKind.KindOcean) as ICCCDefaultAnswer;
                if(answer == null || !answer.CommandSuccessful)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(5));
                    continue;
                }
                else
                {
                    ok = true;
                    break;
                }
            }

            return ok;
        }
        /// <summary>
        /// Converts a message's data into the message. This method is thread-safe!
        /// </summary>
        /// <param name="data">The message's data.</param>
        /// <param name="messagePrototype">The empty message prototype.</param>
        /// <returns>The message containing the data or null.</returns>
        public IICCCMessage convertData2Message(NameValueCollection data, IICCCMessage messagePrototype)
        {
            try
            {
                // Check the preconditions:
                if(data == null || data.Count < 2 || messagePrototype == null) // channel + command = 2
                {
                    return null;
                }

                // Get the type of the message:
                var type = messagePrototype.GetType();

                // Get all properties:
                var properties = type.GetProperties();

                // The .NET ICCC driver is based on properties.
                // In case that the type has no properties, we are
                // done here.
                if (!properties.Any())
                {
                    // We return the prototype, because there are many
                    // messages without any data. Thus, this is a valid case.
                    return messagePrototype;
                }

                // Loop over all data entries:
                foreach(var key in data.AllKeys)
                {
                    // Get the data for this key:
                    var value = data[key];

                    if(key.Contains(':'))
                    {
                        // Decode the base64 encoding. Thus, get the bytes:
                        var valueBytes = Convert.FromBase64String(value);

                        // Split the key into data type and name:
                        var elements = key.Split(':');
                        var dataType = elements[0];
                        var name = elements[1];

                        // Get the matching property:
                        var property = properties.FirstOrDefault(n => n.Name == name);

                        // No property found?
                        if(property == null)
                        {
                            continue;
                        }

                        // Store for the final value:
                        var messageValue = null as object;

                        // For some array convertions:
                        var countNumbers = 0;

                        // Choose the right decoding regarding the data type:
                        switch(dataType)
                        {
                            case "str":
                                // Decode the value:
                                messageValue = Uri.UnescapeDataString(Encoding.UTF8.GetString(valueBytes));
                                break;

                            case "f64":
                                // Decode the value:
                                messageValue = BitConverter.ToDouble(valueBytes, 0);
                                break;

                            case "int":
                                // Decode the value:
                                messageValue = BitConverter.ToInt64(valueBytes, 0);
                                break;

                            case "bool":
                                // Decode the value:
                                messageValue = valueBytes[0] == 0x1 ? true : false;
                                break;

                            case "ui8":
                                // Decode the value:
                                messageValue = valueBytes[0];
                                break;

                            case "ui8[]":
                                // Decode the value:
                                messageValue = valueBytes;
                                break;

                            case "int[]":
                                // Decode the value:
                                countNumbers = valueBytes.Length / 8; // 8 byte per int64 i.e. long
                                messageValue = new long[countNumbers];
                                Buffer.BlockCopy(valueBytes, 0, (Array)messageValue, 0, countNumbers * 8);
                                break;

                            case "bool[]":
                                // Decode the value:
                                messageValue = valueBytes.Select(n => n == 0x0 ? false : true).ToArray();
                                break;

                            case "str[]":
                                // Decode the value:
                                messageValue = Encoding.UTF8.GetString(valueBytes).Split('\n').Select(n => Uri.UnescapeDataString(n)).ToArray();
                                break;

                            case "f64[]":
                                // Decode the value:
                                countNumbers = valueBytes.Length / 8; // 8 byte per float 64 i.e. double
                                messageValue = new double[countNumbers];
                                Buffer.BlockCopy(valueBytes, 0, (Array)messageValue, 0, countNumbers * 8);
                                break;
                        }

                        // Store the value in the message:
                        property.SetValue(messagePrototype, messageValue);
                    }
                }

                return messagePrototype;
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// Converts a message into data. This method is thread-safe!
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>The data object which is may empty.</returns>
        public NameValueCollection convertMessage2Data(IICCCMessage message)
        {
            try
            {
                // The result's data:
                var data = new NameValueCollection();

                // No message?
                if(message == null)
                {
                    return data;
                }

                // Store the channel:
                data.Add("channel", message.getChannel());

                // Store the command:
                data.Add("command", message.getCommand());

                // Get the type of the message:
                var type = message.GetType();

                // Get all properties:
                var properties = type.GetProperties();

                // The .NET ICCC driver is based on properties.
                // In case that the type has no properties, we are
                // done here.
                if(!properties.Any())
                {
                    // We return the current data, because there are many
                    // messages without any additional data. Thus, this is a valid case.
                    return data;
                }

                // Loop over all properties:
                foreach(var property in properties)
                {
                    // Read the type of this property:
                    var dataType = property.PropertyType;

                    // Read the value:
                    var value = property.GetValue(message);

                    // Read the name:
                    var name = property.Name;

                    // Find the matching encoding:
                    switch(dataType.Name)
                    {
                        case "String":
                            data.Add("str:" + name, Convert.ToBase64String(Encoding.UTF8.GetBytes(Uri.EscapeDataString(value as string))));
                            break;

                        case "Int64":
                            data.Add("int:" + name, Convert.ToBase64String(BitConverter.GetBytes((long)value)));
                            break;

                        case "Double":
                            data.Add("f64:" + name, Convert.ToBase64String(BitConverter.GetBytes((double)value)));
                            break;

                        case "Boolean":
                            var boolValue = (bool)value;
                            data.Add("bool:" + name, Convert.ToBase64String(new byte[] { boolValue ? (byte)0x1 : (byte)0x0 }));
                            break;

                        case "Byte":
                            data.Add("ui8:" + name, Convert.ToBase64String(new byte[] { (byte)value }));
                            break;

                        case "Byte[]":
                            data.Add("ui8[]:" + name, Convert.ToBase64String(value as byte[]));
                            break;

                        case "Boolean[]":
                            data.Add("bool[]:" + name, Convert.ToBase64String((value as bool[]).Select(n => n ? (byte)0x1 : (byte)0x0).ToArray()));
                            break;

                        case "Double[]":
                            var doubleData = value as double[];
                            var doubleBuffer = new byte[doubleData.Length*8];
                            Buffer.BlockCopy(doubleData, 0, doubleBuffer, 0, doubleData.Length*8);
                            data.Add("f64[]:" + name, Convert.ToBase64String(doubleBuffer));
                            break;

                        case "Int64[]":
                            var longData = value as long[];
                            var longBuffer = new byte[longData.Length*8];
                            Buffer.BlockCopy(longData, 0, longBuffer, 0, longData.Length*8);
                            data.Add("int[]:" + name, Convert.ToBase64String(longBuffer));
                            break;

                        case "String[]":
                            var strings = value as string[];
                            data.Add("str[]:" + name, Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join("\n", strings.Select(n => Uri.EscapeDataString(n))))));
                            break;
                    }
                }

                return data;
            }
            catch
            {
                return new NameValueCollection();
            }
        }
        /// <summary>
        /// Sends a message to all matching listeners. This method is thread-safe!
        /// </summary>
        /// <param name="message">The message with the channel and command.</param>
        /// <param name="kind">The matching kind of listeners. Thus, you can send a message only to Ocean servers, component servers or to both.</param>
        /// <returns>All received answers.</returns>
        public IEnumerable<IICCCMessage> send2All(IICCCMessage message, byte kind)
        {
            // No message? No answer!
            if(message == null)
            {
                return new IICCCMessage[0];
            }

            // We read the cache, thus, ensure the read access:
            this.cacheLock.EnterReadLock();
            try
            {
                // Convert the message to data:
                var data = ICCCProcessor.INSTANCE.convertMessage2Data(message);

                // No valid message?
                if(data == null || data.Count < 2) // channel + command = 2
                {
                    return new IICCCMessage[0];
                }

                // Get all matching listeners:
                var matchingListeners = this.icccListenerCache.Where(n => n.IsActive && (kind == ICCCKind.KindALL || n.Kind == kind)).Where(n => n.Channel == message.getChannel() && n.Command == message.getCommand()).ToArray();

                // No matching listener?
                if(matchingListeners.Length == 0)
                {
                    return new IICCCMessage[0];
                }

                // Space for all threads and results:
                var tasks = new Task<IICCCMessage>[matchingListeners.Length];

                // Loop over all matching listeners:
                for(var n = 0; n < matchingListeners.Length; n++)
                {
                    // Get an listener:
                    var listener = matchingListeners[n];

                    // Start a new thread:
                    tasks[n] = Task.Run<IICCCMessage>(() =>
                    {
                        // Send the message and read the answer:
                      	var answerData = this.sendMessage(data, listener);

                      	// Create another empty instance for the answer:
                      	var type = message.getAnswerObject().GetType();
                      	var answerObj = type.GetConstructors().First(info => !info.GetParameters().Any()).Invoke(null) as IICCCMessage;

                      	// Create the answer's message and return it:
                      	return ICCCProcessor.INSTANCE.convertData2Message(answerData, answerObj);
                    });
                }

                // Wait for all answers:
                Task.WaitAll(tasks);
                return tasks.Where(n => n.Result != null).Select(t => t.Result).ToArray();
            }
            catch
            {
                return new IICCCMessage[0];
            }
            finally
            {
                this.cacheLock.ExitReadLock();
            }
        }
        /// <summary>
        /// Sends a message to any matching listener. This method is thread-safe!
        /// </summary>
        /// <param name="message">The message with the channel and command.</param>
        /// <param name="kind">The matching kind of listeners. Thus, you can send a message only to an Ocean server, component server or to both.</param>
        /// <returns>The received answer or null.</returns>
        public IICCCMessage send2Any(IICCCMessage message, byte kind)
        {
            // No message? No answer!
            if(message == null)
            {
                return null;
            }

            // We read the cache, thus, ensure the read access:
            this.cacheLock.EnterReadLock();
            try
            {
                // Convert the message to data:
                var data = ICCCProcessor.INSTANCE.convertMessage2Data(message);

                // No valid message?
                if(data == null || data.Count < 2) // channel + command = 2
                {
                    return null;
                }

                // Get all matching listeners:
                var matchingListeners = this.icccListenerCache.Where(n => n.IsActive && (kind == ICCCKind.KindALL || n.Kind == kind)).Where(n => n.Channel == message.getChannel() && n.Command == message.getCommand()).ToArray();

                // The chosen listener:
                var chosenListener = null as ICCCListener;

                // No matching listener?
                if(matchingListeners.Length == 0)
                {
                    return null;
                }

                if(matchingListeners.Length == 1)
                {
                    // Take the only one:
                    chosenListener = matchingListeners[0];
                }
                else
                {
                    // Choose a random listener:
                    chosenListener = matchingListeners[BetterRND.INSTANCE.nextInt(0, matchingListeners.Length)];
                }

                // Send the message and read the answer:
              	var answerData = this.sendMessage(data, chosenListener);

              	// Create the answer's message and return it:
              	return ICCCProcessor.INSTANCE.convertData2Message(answerData, message.getAnswerObject());
            }
            catch
            {
                return null;
            }
            finally
            {
                this.cacheLock.ExitReadLock();
            }
        }