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); }
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); }