Пример #1
0
        /// <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();
            }
        }
Пример #2
0
        /// <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();
            }
        }
Пример #3
0
        /// <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();
            }
        }