diff --git a/dbService.py b/dbService.py index 3227558..0cc791c 100644 --- a/dbService.py +++ b/dbService.py @@ -72,96 +72,36 @@ class MessageDbService(MultiDeviceDbSupport): c = collection.find(payload).sort("ts", DESCENDING).skip(offset).limit(limit) return await c.to_list() -class NodeDbService(MultiDeviceDbSupport): +class PacketDbService(MultiDeviceDbSupport): def __init__(self, dbStore, core): super().__init__(dbStore, core) - async def listOfNodes(self, devices = []): - pipeline = [ #ai slooop - {"$match": {"$or": self.deviceHash2Match(devices)}}, - # Сортировка для каждого num по убыванию ts - {"$sort": {"num": 1, "ts": -1}}, - # Группировка по num и взятие первого (последнего) документа - {"$group": { - "_id": "$num", - "latest_doc": {"$first": "$$ROOT"} - }}, - # Замена корневого документа - {"$replaceRoot": {"newRoot": "$latest_doc"}}, - # Сортировка результата (опционально) - {"$sort": {"num": 1}} - ] + async def findLastPackets(self, nums: List[int] = [], portnums: List[int] = []): + pipeline = [] + match = {} - collection = self.dbStore['node_info'] - c = await collection.aggregate(pipeline) - return await c.to_list() - - async def listOfDirectNodes(self, devices = []): - pipeline = [ #ai slooop - {"$match": {"hops_away": 0, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку - # Сортировка для каждого num по убыванию ts - {"$sort": {"num": 1, "ts": -1}}, - # Группировка по num и взятие первого (последнего) документа + if nums: + match["from"] = {"$in": nums} + + if portnums: + match["portnum"] = {"$in": portnums} + + if match: + pipeline += [{"$match":match}] + + pipeline += [ + {"$sort": {"from": 1, "ts": -1}}, {"$group": { - "_id": "$num", + "_id": "$from", "latest_doc": {"$first": "$$ROOT"} }}, - # Замена корневого документа {"$replaceRoot": {"newRoot": "$latest_doc"}}, - # Сортировка результата (опционально) - {"$sort": {"num": 1}} - ] - - collection = self.dbStore['node_info'] - c = await collection.aggregate(pipeline) - return await c.to_list() - - async def oneNode(self, num: int, devices = []): - collection = self.dbStore['node_info'] - c = await collection.find_one( - {"num":int(num), "$or": self.deviceHash2Match(devices)}, - sort=[("ts", -1)] - ) - return c - - async def listOfSelectedNodes(self, nums: List[int], devices = []): - pipeline = [ - {"$match": {"num": {"$in": nums}, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку - {"$sort": {"num": 1, "ts": -1}}, # Сортируем по num и ts (по убыванию) - { - "$group": { - "_id": "$num", # Группируем по num - "latest_doc": {"$first": "$$ROOT"} # Берем первую (последнюю по ts) - } - }, - {"$replaceRoot": {"newRoot": "$latest_doc"}}, # Восстанавливаем структуру - {"$sort": {"num": 1}} # Сортируем результат по num - ] - collection = self.dbStore['node_info'] - c = await collection.aggregate(pipeline) - return await c.to_list() - - async def listOfFindLikeName(self, long_name, devices = []): - pipeline = [ - {"$match": {"long_name": {"$regex":long_name ,'$options' : 'i'}, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку - {"$sort": {"num": 1, "ts": -1}}, # Сортируем по num и ts (по убыванию) - { - "$group": { - "_id": "$num", # Группируем по num - "latest_doc": {"$first": "$$ROOT"} # Берем первую (последнюю по ts) - } - }, - {"$replaceRoot": {"newRoot": "$latest_doc"}}, # Восстанавливаем структуру - {"$sort": {"num": 1}} # Сортируем результат по num + {"$sort": {"from": 1}} ] - collection = self.dbStore['node_info'] + collection = self.dbStore['packet'] c = await collection.aggregate(pipeline) return await c.to_list() -class PacketDbService(MultiDeviceDbSupport): - def __init__(self, dbStore, core): - super().__init__(dbStore, core) - async def findPacketsSignals(self, after: float = -1, before: float = -1, @@ -248,6 +188,145 @@ class PacketDbService(MultiDeviceDbSupport): c = await collection.aggregate(pipeline) l = await c.to_list() return [PacketGroup(p, packetsPerNode, packetsSumNode) for p in l] + +class NodeDbService(PacketDbService, MultiDeviceDbSupport): + def __init__(self, dbStore, core): + PacketDbService.__init__(self, dbStore, core) + MultiDeviceDbSupport.__init__(self, dbStore, core) + + async def fillNodeFromPacketCollection(self, l): + nums = [node.get("num", 0) for node in l] + + #ищем сначала ноды с позицией 3 портнум + packet_pos_nodes = await self.findLastPackets(nums, [3])#### + packet_pos_nodes_dict = {}### + for packet in packet_pos_nodes: + packet_pos_nodes_dict[packet.get("from")] = packet + nums_with_pos = [node.get("from", 0) for node in packet_pos_nodes] + + #смотрим какие пакеты от нод имеют позицию, и делаем список нод где нет ее + nums_without_pos = [fr0m for fr0m in nums if fr0m not in nums_with_pos] + packet_without_pos = await self.findLastPackets(nums_without_pos, [])#### + packet_without_pos_dict = {} + for packet in packet_without_pos: + packet_without_pos_dict[packet.get("from")] = packet + + #суем свежачок + new_nodes_list = [] + def fillNodeBaseData(node, d1ct): + ## base packet + if d1ct[node["num"]].get("rx_snr", None) != None: + node["snr"] = d1ct[node["num"]]["rx_snr"] + if d1ct[node["num"]].get("rx_rssi", None) != None: + node["rssi"] = d1ct[node["num"]]["rx_rssi"] + if d1ct[node["num"]].get("ts", None) != None: + node["ts"] = d1ct[node["num"]]["ts"] + if d1ct[node["num"]].get("hop_start", None) != None and d1ct[node["num"]].get("hop_limit", None) != None: + node["hops_away"] = d1ct[node["num"]].get("hop_start", 0) - d1ct[node["num"]].get("hop_limit", 0) + if d1ct[node["num"]].get("portnum", None) != None: + node["last_portnum"] = d1ct[node["num"]].get("portnum", None) + return node + + for node in l: + node["view_in_packets"] = True + if node.get("num", 0) in packet_pos_nodes_dict.keys(): + if packet_pos_nodes_dict[node["num"]].get("decoded_payload_object", {}): + node["position"] = packet_pos_nodes_dict[node["num"]]["decoded_payload_object"] + + node = fillNodeBaseData(node, packet_pos_nodes_dict) + elif node.get("num", 0) in packet_without_pos_dict.keys(): + node = fillNodeBaseData(node, packet_without_pos_dict) + else: + node["view_in_packets"] = False + + new_nodes_list.append(node) + + return new_nodes_list + + async def listOfNodes(self, devices = []): + pipeline = [ #ai slooop + {"$match": {"$or": self.deviceHash2Match(devices)}}, + # Сортировка для каждого num по убыванию ts + {"$sort": {"num": 1, "ts": -1}}, + # Группировка по num и взятие первого (последнего) документа + {"$group": { + "_id": "$num", + "latest_doc": {"$first": "$$ROOT"} + }}, + # Замена корневого документа + {"$replaceRoot": {"newRoot": "$latest_doc"}}, + # Сортировка результата (опционально) + {"$sort": {"num": 1}} + ] + + collection = self.dbStore['node_info'] + c = await collection.aggregate(pipeline) + l = await c.to_list() + return await self.fillNodeFromPacketCollection(l) + + async def listOfDirectNodes(self, devices = []): + pipeline = [ #ai slooop + {"$match": {"hops_away": 0, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку + # Сортировка для каждого num по убыванию ts + {"$sort": {"num": 1, "ts": -1}}, + # Группировка по num и взятие первого (последнего) документа + {"$group": { + "_id": "$num", + "latest_doc": {"$first": "$$ROOT"} + }}, + # Замена корневого документа + {"$replaceRoot": {"newRoot": "$latest_doc"}}, + # Сортировка результата (опционально) + {"$sort": {"num": 1}} + ] + + collection = self.dbStore['node_info'] + c = await collection.aggregate(pipeline) + l = await c.to_list() + return await self.fillNodeFromPacketCollection(l) + + async def oneNode(self, num: int, devices = []): + collection = self.dbStore['node_info'] + c = await collection.find_one( + {"num":int(num), "$or": self.deviceHash2Match(devices)}, + sort=[("ts", -1)] + ) + return await self.fillNodeFromPacketCollection([c]) + + async def listOfSelectedNodes(self, nums: List[int], devices = []): + pipeline = [ + {"$match": {"num": {"$in": nums}, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку + {"$sort": {"num": 1, "ts": -1}}, # Сортируем по num и ts (по убыванию) + { + "$group": { + "_id": "$num", # Группируем по num + "latest_doc": {"$first": "$$ROOT"} # Берем первую (последнюю по ts) + } + }, + {"$replaceRoot": {"newRoot": "$latest_doc"}}, # Восстанавливаем структуру + {"$sort": {"num": 1}} # Сортируем результат по num + ] + collection = self.dbStore['node_info'] + c = await collection.aggregate(pipeline) + l = await c.to_list() + return await self.fillNodeFromPacketCollection(l) + + async def listOfFindLikeName(self, long_name, devices = []): + pipeline = [ + {"$match": {"long_name": {"$regex":long_name ,'$options' : 'i'}, "$or": self.deviceHash2Match(devices)}}, # Фильтруем по списку + {"$sort": {"num": 1, "ts": -1}}, # Сортируем по num и ts (по убыванию) + { + "$group": { + "_id": "$num", # Группируем по num + "latest_doc": {"$first": "$$ROOT"} # Берем первую (последнюю по ts) + } + }, + {"$replaceRoot": {"newRoot": "$latest_doc"}}, # Восстанавливаем структуру + {"$sort": {"num": 1}} # Сортируем результат по num + ] + collection = self.dbStore['node_info'] + c = await collection.aggregate(pipeline) + return await c.to_list() #no need fill, just search class DbService(NodeDbService, PacketDbService, MessageDbService): def __init__(self, dbStore, core): diff --git a/webExtensions/extra/NodeDTO.py b/webExtensions/extra/NodeDTO.py index 1b9123e..94b74e7 100644 --- a/webExtensions/extra/NodeDTO.py +++ b/webExtensions/extra/NodeDTO.py @@ -1,4 +1,4 @@ -__slots__ = ["num", "snr", "hops_away", "ts", "long_name", "short_name", "is_unmessagable"] +__slots__ = ["num", "snr", "rssi", "hops_away", "ts", "long_name", "short_name", "is_unmessagable", "last_portnum", "view_in_packets"] class NodeDTO: def __init__(self, data, grabPosition = False, grabMetrics = False):