private HashSet <string> GetNonExistingMappingFields(IReadOnlyMap <string, string> fieldsMapping)
        {
            var nonExistingFields = new HashSet <string>();

            string mappedFieldName;

            foreach (var fieldName in base.GetFieldNames())
            {
                if (!fieldsMapping.TryGetKey(fieldName, out mappedFieldName))
                {
                    // If nothing maps into current field - ignore
                    continue;
                }

                // There is a mapping that results into already existing field, preserve source field name
                nonExistingFields.Add(mappedFieldName);
            }

            // All preserved source field names should be ignored (should not belong to data item), otherwise we have a conflict
            foreach (var fieldName in base.GetFieldNames())
            {
                if (nonExistingFields.Contains(fieldName) &&
                    // this is not a check, just get target field name for the exception message
                    fieldsMapping.TryGetValue(fieldName, out mappedFieldName))
                {
                    throw Errors.DataItemAlreadyContainsField(mappedFieldName);
                }
            }

            return(nonExistingFields);
        }
 public RemappedFieldsDataItem(IDataItem dataItem, IReadOnlyMap<string, string> fieldsMapping)
     : base(dataItem)
 {
     Guard.NotNull("fieldsMapping", fieldsMapping);
     this.fieldsMapping = fieldsMapping;
     inactiveMappings = GetNonExistingMappingFields(fieldsMapping);
 }
 public RemappedFieldsDataItem(IDataItem dataItem, IReadOnlyMap <string, string> fieldsMapping)
     : base(dataItem)
 {
     Guard.NotNull("fieldsMapping", fieldsMapping);
     this.fieldsMapping = fieldsMapping;
     inactiveMappings   = GetNonExistingMappingFields(fieldsMapping);
 }
Example #4
0
 public FunctionHandlerContext(IpiSensorNetConfiguration moduleConfiguration, PiSensorNetDbContext databaseContext, IReadOnlyDictionary <FunctionTypeEnum, IQueryableFunctionHandler> queryableFunctionHandlers, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, IReadOnlyMap <string, int> functionNames, IReadOnlyDictionary <TriggerSourceTypeEnum, ITriggerSourceHandler> triggerSourceHandlers, IReadOnlyDictionary <int, TriggerDelegate> triggerDelegates, IReadOnlyDictionary <TriggerDependencyTypeEnum, ITriggerDependencyHandler> triggerDependencyHandlers, DateTime triggerDateTime)
     : base(databaseContext, triggerSourceHandlers, triggerDelegates, triggerDependencyHandlers, triggerDateTime)
 {
     ModuleConfiguration       = moduleConfiguration;
     QueryableFunctionHandlers = queryableFunctionHandlers;
     FunctionTypes             = functionTypes;
     FunctionNames             = functionNames;
 }
Example #5
0
        public static string GetOrEmpty(this IReadOnlyMap <string, string> coll, string key)
        {
            if (!coll.Contains(key))
            {
                return(string.Empty);
            }

            return(coll[key] ?? string.Empty);
        }
Example #6
0
//        public static IEnumerable<TValue> GetOrNull<TKey, TValue>(this IReadOnlyMap<TKey, TValue> coll, TKey key)
//        {
//            if (!coll.Contains(key))
//            {
//                return null;
//            }
//
//            return coll[key];
//        }

//        public static IEnumerable<TValue> GetOrEmpty<TKey, TValue>(this IReadOnlyMap<TKey, TValue> coll, TKey key)
//        {
//            if (!coll.Contains(key))
//            {
//                return new TValue[0];
//            }
//
//            return coll[key];
//        }

        public static TValue GetOrNull <TKey, TValue>(this IReadOnlyMap <TKey, TValue> coll, TKey key)
        {
            if (!coll.Contains(key))
            {
                return(default(TValue));
            }

            return(coll[key]);
        }
Example #7
0
        public static string Write(IReadOnlyMap <string, string> flash)
        {
            List <string> sb = new List <string>();

            foreach (var key in flash.Keys)
            {
                sb.Add(string.Concat(Uri.EscapeDataString(key), "=", Uri.EscapeDataString(flash[key] ?? string.Empty)));
            }

            return(string.Join("&", sb));
        }
Example #8
0
        // ReSharper disable once UnusedMember.Local
        private static void Demo(IpiSensorNetConfiguration moduleConfiguration, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, IReadOnlyMap <string, int> functionNames, IReadOnlyDictionary <FunctionTypeEnum, IFunctionHandler> functionHandlers, IReadOnlyDictionary <FunctionTypeEnum, IQueryableFunctionHandler> queryableFunctionHandlers, IReadOnlyDictionary <TriggerSourceTypeEnum, ITriggerSourceHandler> triggerSourceHandlers, IReadOnlyDictionary <int, TriggerDelegate> triggerDelegates, IReadOnlyDictionary <TriggerDependencyTypeEnum, ITriggerDependencyHandler> triggerDependencyHandlers)
        {
            using (var context = PiSensorNetDbContext.Connect(moduleConfiguration.ConnectionString).WithChangeTracking())
            {
                var functionID   = context.Functions.AsNoTracking().Where(i => i.FunctionType == FunctionTypeEnum.FunctionList).Select(i => i.ID).Single();
                var moduleNumber = context.Modules.AsNoTracking().Count() + 1;
                var address      = $"test{moduleNumber}";

                context.Modules
                .Add(new Module(address)
                {
                    FriendlyName = address,
                    Description  = "Test module",
                }
                     .For(i => { i.ModuleFunctions.Add(context.Functions.Select(f => new ModuleFunction(i, f))); })
                     .For(i =>
                {
                    i.Packets.Add(new[]
                    {
                        new Packet(i, 0, "identify;function_list;voltage;report;ow_list;ow_ds18b20_temperature;ow_ds18b20_temperature_periodical;", DateTime.Now)
                        // "2854280E02000070|25.75;28AC5F2600008030|25.75;"
                        {
                            FunctionID = functionID,
                        }
                    });
                })
                     );

                context.SaveChanges();

                var module = context.Modules.AsNoTracking().Where(i => i.Address == address).Single();
                var packet = context.Packets.Include(i => i.Function).AsNoTracking().Where(i => i.ModuleID == module.ID).OrderByDescending(i => i.Created).First();

                // ReSharper disable once PossibleInvalidOperationException
                var functionHandler = functionHandlers[packet.Function.FunctionType];
                var taskQueue       = new HubMessageQueue();

                functionHandler.Handle(new FunctionHandlerContext(moduleConfiguration, context, queryableFunctionHandlers, functionTypes, functionNames, triggerSourceHandlers, triggerDelegates, triggerDependencyHandlers, DateTime.Now), packet, ref taskQueue);

                context.SaveChanges();
            }
        }
Example #9
0
        private static void BuildCache()
        {
            using (var context = PiSensorNetDbContext.Connect(Configuration.ConnectionString))
            {
                ModuleAddresses = CacheModuleAddresses(context);

                var cachedFunctions = CacheFunctions(context);
                FunctionTypes = cachedFunctions.Item1;
                FunctionNames = cachedFunctions.Item2;

                var cachedFunctionHandlers = CacheFunctionHandlers();
                FunctionHandlers          = cachedFunctionHandlers.Item1;
                QueryableFunctionHandlers = cachedFunctionHandlers.Item2;

                TriggerSourceHandlers     = CacheTriggerSourceHandlers();
                TriggerDependencyHandlers = CacheTriggerDependencyHandlers();

                var cachedTriggerSources = CacheTriggerSources(context, TriggerDependencyHandlers);
                TriggerSources   = cachedTriggerSources.Item1;
                TriggerDelegates = cachedTriggerSources.Item2;
            }

            ToConsole("BuildCache: Cache built!");
        }
        private HashSet<string> GetNonExistingMappingFields(IReadOnlyMap<string, string> fieldsMapping)
        {
            var nonExistingFields = new HashSet<string>();

            string mappedFieldName;
            foreach (var fieldName in base.GetFieldNames())
            {
                if (!fieldsMapping.TryGetKey(fieldName, out mappedFieldName))
                    // If nothing maps into current field - ignore
                    continue;

                // There is a mapping that results into already existing field, preserve source field name
                nonExistingFields.Add(mappedFieldName);
            }

            // All preserved source field names should be ignored (should not belong to data item), otherwise we have a conflict
            foreach (var fieldName in base.GetFieldNames())
                if (nonExistingFields.Contains(fieldName) &&
                    // this is not a check, just get target field name for the exception message
                    fieldsMapping.TryGetValue(fieldName, out mappedFieldName))
                    throw Errors.DataItemAlreadyContainsField(mappedFieldName);

            return nonExistingFields;
        }
Example #11
0
 public static string Write(IReadOnlyMap <string, string> collection)
 {
     return(WriteInternal(collection, key => new[] { collection[key] ?? string.Empty }));
 }
Example #12
0
 public static IReadOnlyMap <TForwardKey, TReverseKey> ReadOnly <TForwardKey, TReverseKey>([CanBeNull] this IReadOnlyMap <TForwardKey, TReverseKey> map)
 => map;
Example #13
0
 public static TKey TryGetValue <TKey, TValue>(this IReadOnlyMap <TKey, TValue> map, TValue key, TKey defaultValue = default)
 {
     return(TryGetValue(map, key, out TKey result) ? result : defaultValue);
 }
Example #14
0
 public static Boolean TryGetValue <TKey, TValue>(this IReadOnlyMap <TKey, TValue> map, TValue key, out TKey result)
 {
     return(map.TryGetValue(key, out result));
 }
Example #15
0
 public MapManager(IReadOnlyMap map)
 {
     Map = map;
 }
Example #16
0
        internal static bool MergePackets(PiSensorNetDbContext context, IpiSensorNetConfiguration moduleConfiguration, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, IReadOnlyMap <string, int> functionNames, IReadOnlyMap <string, int> moduleAddresses, CacheModuleAddressesDelegate cacheModuleAddresses, Action <string> logger)
        {
            logger("MergePackets: Start...");

            var partialPackets = context.PartialPackets
                                 .AsNoTracking()
                                 .Where(i => i.State == PartialPacketStateEnum.New)
                                 .ToList();

            //logger("MergePackets: Done selecting..."); // ~14ms

            var groupedPackets = partialPackets.GroupBy(i => new
            {
                i.Address,
                i.Number,
                i.Total
            })
                                 .ToList();

            var newModules = new Dictionary <string, Module>();

            foreach (var packetGroup in groupedPackets)
            {
                var address = packetGroup.Key.Address;

                if (moduleAddresses.Forward.ContainsKey(address) || newModules.ContainsKey(address))
                {
                    continue;
                }

                var module = new Module(address);

                context.Modules.Add(module);

                newModules.Add(address, module);
            }

            if (newModules.Count > 0)
            {
                logger("MergePackets: Done finding modules...");

                context.SaveChanges();

                logger("MergePackets: Done saving modules...");

                moduleAddresses = cacheModuleAddresses(context);
            }

            logger($"MergePackets: Done creating new modules, found {newModules.Count}!"); // 700us, no modules

            var packetGroupWithPacket = new List <Tuple <Packet, IEnumerable <PartialPacket> > >(groupedPackets.Count);

            foreach (var packetGroup in groupedPackets)
            {
                if (packetGroup.Count() != packetGroup.Key.Total)
                {
                    context.EnqueueUpdate <PartialPacket>(
                        i => i.State == PartialPacketStateEnum.Fragmented,
                        i => packetGroup.Select(ii => ii.ID).Contains(i.ID));

                    continue;
                }

                var moduleID  = moduleAddresses.Forward[packetGroup.Key.Address];
                int?messageID = null;
                var text      = packetGroup.OrderBy(i => i.Current).Select(i => i.Message).Concat();
                var received  = packetGroup.Max(i => i.Received);

                var messageIDDelimiterIndex = text.IndexOf(moduleConfiguration.MessageIDDelimiter);
                if (messageIDDelimiterIndex > 0)
                {
                    messageID = text.Substring(0, messageIDDelimiterIndex).FromBase36();
                    text      = text.Substring(messageIDDelimiterIndex + 1);
                }

                var functionName = text.SubstringBefore(moduleConfiguration.FunctionResultNameDelimiter).ToLowerInvariant();
                var functionID   = functionNames.Forward.GetValueOrNullable(functionName);

                if (functionID.HasValue)
                {
                    text = text.Substring(functionName.Length + 1);
                }

                var packet = new Packet(moduleID, packetGroup.Key.Number, text, received)
                {
                    MessageID  = messageID,
                    FunctionID = functionID,
                };

                context.Packets.Add(packet);

                packetGroupWithPacket.Add(Tuple.Create(packet, (IEnumerable <PartialPacket>)packetGroup));
            }

            if (packetGroupWithPacket.Count > 0)
            {
                //logger("MergePackets: Done parsing packet groups!"); // ~3ms

                context.SaveChanges();

                logger("MergePackets: Saved changes!"); // ~23ms

                packetGroupWithPacket.Each(p =>
                                           context.EnqueueUpdate <PartialPacket>(
                                               i => i.PacketID == p.Item1.ID && i.State == PartialPacketStateEnum.Merged,
                                               i => p.Item2.Select(ii => ii.ID).Contains(i.ID)));

                context.ExecuteRaw();

                logger("MergePackets: Updated partial packets!"); // ~15ms, 1 packet
            }

            logger($"MergePackets: Done, created {packetGroupWithPacket.Count} packet(s)!");

            return(packetGroupWithPacket.Count > 0);
        }
Example #17
0
 public RemapFieldsTransformation(IReadOnlyMap <string, string> fieldsMapping)
 {
     this.fieldsMapping = fieldsMapping;
 }
Example #18
0
        internal static void HandleMessage(string clientID, int?moduleID, FunctionTypeEnum functionType, bool isQuery, string text, IReadOnlyMap <string, int> moduleAddresses, IpiSensorNetConfiguration moduleConfiguration, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, IHubProxy hubProxy, Action <string> logger)
        {
            logger($"HandleMessage: Received message from ${clientID} to @{moduleID?.ToString() ?? "ALL"} - {functionType}{(text == null ? (isQuery ? "?" : String.Empty) : ":" + text)}");

            if (moduleID.HasValue && !moduleAddresses.Reverse.ContainsKey(moduleID.Value))
            {
                hubProxy.Invoke("error", clientID, $"Module #{moduleID.Value} does not exist.");

                logger($"HandleMessage: ERROR: Message not handled, module #{moduleID.Value} does not exist!");

                return;
            }

            int messageID;

            using (var context = PiSensorNetDbContext.Connect(moduleConfiguration.ConnectionString))
            {
                var message = new Message(functionTypes.Forward[functionType], isQuery)
                {
                    ModuleID = moduleID,
                };

                if (!isQuery)
                {
                    message.Text = text;
                }

                context.Messages.Add(message);

                context.SaveChanges();

                messageID = message.ID;
            }

            logger($"HandleMessage: Message handled to #{messageID}!"); // ~38ms
        }
Example #19
0
        private static IHubProxy InitializeHubConnection(IReadOnlyConfiguration configuration, IpiSensorNetConfiguration moduleConfiguration, MessageHandler handler, IReadOnlyMap <string, int> moduleAddresses, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, int?serialProcessID, DisposalQueue toDispose, Action <string> logger)
        {
            var hubConnection = new HubConnection(configuration["Settings:WebAddress"],
                                                  new Dictionary <string, string>
            {
                {
                    configuration["Settings:SignalREngineFlagName"], true.ToString().ToLowerInvariant()
                }
            });

            hubConnection.StateChanged += change => logger($"InitializeHubConnection: StateChanged: '{change.OldState}' -> '{change.NewState}'!");

            hubConnection.JsonSerializer.Converters.Add(new NullConverter()); // handle NULLs

            var hubProxy = hubConnection.CreateHubProxy(configuration["Settings:SignalRHubName"]);

            toDispose += hubProxy.On <string, int?, FunctionTypeEnum, string>("sendMessage",
                                                                              (clientID, moduleID, functionType, text)
                                                                              => handler(clientID, moduleID, functionType, false, text, moduleAddresses, moduleConfiguration, functionTypes, serialProcessID, hubProxy, logger));

            toDispose += hubProxy.On <string, int?, FunctionTypeEnum>("sendQuery",
                                                                      (clientID, moduleID, functionType)
                                                                      => handler(clientID, moduleID, functionType, true, null, moduleAddresses, moduleConfiguration, functionTypes, serialProcessID, hubProxy, logger));

            try
            {
                hubConnection.Start().Wait();
            }
            catch (Exception e)
            {
                logger($"InitializeHubConnection: ERROR: Exception occurred while initializing hub connection: {e.Message}.");

                return(null);
            }

            logger($"InitializeHubConnection: Connection to hub started with ID '{hubConnection.ConnectionId}'!");

            toDispose += hubConnection;

            return(hubProxy);
        }
Example #20
0
        private static void InternalHandleMessage(string clientID, int?moduleID, FunctionTypeEnum functionType, bool isQuery, string text, IReadOnlyMap <string, int> modules, IpiSensorNetConfiguration moduleConfiguration, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, int?serialProcessID, IHubProxy hubProxy, Action <string> logger)
        {
            HandleMessage(clientID, moduleID, functionType, isQuery, text, modules, moduleConfiguration, functionTypes, hubProxy, logger);

            if (serialProcessID.HasValue)
            {
                Signal.Send(serialProcessID.Value, SignalTypeEnum.User1);
            }
        }
Example #21
0
 public static System.Collections.IDictionary CreateObjectIDictionary <TKey, TValue>(IReadOnlyMap <TKey, TValue> map)
 {
     return(new ObjectDictionaryShim <TKey, TValue>(map));
 }
Example #22
0
 public static IDictionary <TKey, TValue> CreateIDictionary <TKey, TValue>(IReadOnlyMap <TKey, TValue> map)
 {
     return(new DictionaryShim <TKey, TValue>(map));
 }
Example #23
0
 internal ObjectDictionaryShim(IReadOnlyMap <TKey, TValue> map)
 {
     m_map = map;
 }
 public RemapFieldsTransformation(IReadOnlyMap<string, string> fieldsMapping)
 {
     this.fieldsMapping = fieldsMapping;
 }
Example #25
0
        internal static bool HandlePackets(PiSensorNetDbContext context, IpiSensorNetConfiguration moduleConfiguration, IReadOnlyMap <FunctionTypeEnum, int> functionTypes, IReadOnlyMap <string, int> functionNames, IReadOnlyDictionary <FunctionTypeEnum, IFunctionHandler> functionHandlers, IReadOnlyDictionary <FunctionTypeEnum, IQueryableFunctionHandler> queryableFunctionHandlers, IReadOnlyDictionary <TriggerSourceTypeEnum, ITriggerSourceHandler> triggerSourceHandlers, IReadOnlyDictionary <int, TriggerDelegate> triggerDelegates, IReadOnlyDictionary <TriggerDependencyTypeEnum, ITriggerDependencyHandler> triggerDependencyHandlers, int?serialProcessID, IHubProxy hubProxy, Action <string> logger)
        {
            logger("HandlePackets: Start...");

            var packets = context.Packets
                          .Include(i => i.Module)
                          .Include(i => i.Function)
                          .Where(i => i.State == PacketStateEnum.New)
                          .Where(i => i.FunctionID.HasValue)
                          .OrderBy(i => i.Received)
                          .ToList();

            logger("HandlePackets: Done selecting..."); // ~21ms

            if (packets.Count == 0)
            {
                return(false);
            }

            var handlerContext = new FunctionHandlerContext(moduleConfiguration, context, queryableFunctionHandlers, functionTypes, functionNames, triggerSourceHandlers, triggerDelegates, triggerDependencyHandlers, DateTime.Now);

            var handleAgain     = false;
            var newMesagesAdded = false;
            var hubTasksQueue   = new HubMessageQueue();

            foreach (var packet in packets)
            {
                // ReSharper disable once PossibleInvalidOperationException
                var handler = functionHandlers.GetValueOrDefault(packet.Function.FunctionType);
                if (handler == null)
                {
                    context.EnqueueUpdate <Packet>(
                        i => i.State == PacketStateEnum.Unhandled,
                        i => i.ID == packet.ID);

                    logger($"HandlePackets: Packet #{packet.ID} (function '{packet.Function.FunctionType}') could not be handled, no handler found!");

                    continue;
                }

                var functionHandlerResult = handler.IsModuleIdentityRequired && packet.Module.State != ModuleStateEnum.Identified
                    ? PacketStateEnum.Skipped
                    : handler.Handle(handlerContext, packet, ref hubTasksQueue);

                handleAgain     = handleAgain || functionHandlerResult.ShouldHandlePacketsAgain;
                newMesagesAdded = newMesagesAdded || functionHandlerResult.NewMessagesAdded;

                context.EnqueueUpdate <Packet>(
                    i => i.State == functionHandlerResult.PacketState && i.Processed == DateTime.Now,
                    i => i.ID == packet.ID);

                if (handler.TriggerSourceType.HasValue && functionHandlerResult.PacketState == PacketStateEnum.Handled)
                {
                    TriggerSources[handler.TriggerSourceType.Value].Each(i =>
                                                                         TriggerSourceHandlerHelper.Handle(handlerContext, i, packet.Module.ID));
                }

                logger($"HandlePackets: Packet #{packet.ID} processed to '{functionHandlerResult.PacketState}'" +
                       $"{(functionHandlerResult.NewMessagesAdded ? ", new messaged were added" : String.Empty)}" +
                       $"{(functionHandlerResult.ShouldHandlePacketsAgain ? ", requested another handling" : String.Empty)}" +
                       "!");
            }

            logger($"HandlePackets: Done handling packets, processed {packets.Count}!"); // ~51ms

            context.ExecuteRaw();

            logger("HandlePackets: Queries executed!"); // ~13ms

            if (newMesagesAdded && serialProcessID.HasValue)
            {
                Signal.Send(serialProcessID.Value, SignalTypeEnum.User1);
            }

            while (hubTasksQueue.Count > 0)
            {
                hubProxy.SafeInvoke(hubTasksQueue.Dequeue());
            }

            logger($"HandlePackets: Hub message(s) sent{(newMesagesAdded ? ", Serial signaled about new message(s)" : String.Empty)}{(handleAgain ? ", packet(s) will be handled again" : String.Empty)}!"); // ~10ms

            return(handleAgain);
        }