|
3 | 3 | """ |
4 | 4 |
|
5 | 5 | import abc |
| 6 | +import json |
6 | 7 | from typing import Dict, List, Set, Any |
7 | 8 |
|
8 | 9 | import werkzeug.exceptions |
|
15 | 16 | from app.util.converters import IdentifierToBase64URLConverter |
16 | 17 | from app.interfaces.base import BaseWSGIApp, HTTPApiDecoder |
17 | 18 | from app import model as server_model |
18 | | -from app.adapter.jsonization import ServerAASToJsonEncoder |
| 19 | +from app.adapter import jsonization |
19 | 20 |
|
20 | | -encoder=ServerAASToJsonEncoder() |
21 | 21 |
|
22 | | -class AbstractDiscoveryStore(metaclass=abc.ABCMeta): |
23 | | - aas_id_to_asset_ids: Any |
24 | | - asset_id_to_aas_ids: Any |
25 | | - |
26 | | - @abc.abstractmethod |
27 | | - def __init__(self): |
28 | | - pass |
29 | | - |
30 | | - @abc.abstractmethod |
31 | | - def get_all_specific_asset_ids_by_aas_id(self, aas_id: model.Identifier) -> List[model.SpecificAssetId]: |
32 | | - pass |
33 | | - |
34 | | - @abc.abstractmethod |
35 | | - def add_specific_asset_ids_to_aas(self, aas_id: model.Identifier, asset_ids: List[model.SpecificAssetId]) -> None: |
36 | | - pass |
37 | | - |
38 | | - @abc.abstractmethod |
39 | | - def delete_specific_asset_ids_by_aas_id(self, aas_id: model.Identifier) -> None: |
40 | | - pass |
41 | | - |
42 | | - @abc.abstractmethod |
43 | | - def search_aas_ids_by_asset_link(self, asset_link: server_model.AssetLink) -> List[model.Identifier]: |
44 | | - pass |
45 | | - |
46 | | - @abc.abstractmethod |
47 | | - def _add_aas_id_to_specific_asset_id(self, asset_id: model.SpecificAssetId, aas_identifier: model.Identifier) -> None: |
48 | | - pass |
49 | | - |
50 | | - @abc.abstractmethod |
51 | | - def _delete_aas_id_from_specific_asset_ids(self, asset_id: model.SpecificAssetId, aas_id: model.Identifier) -> None: |
52 | | - pass |
53 | | - |
54 | | - |
55 | | - |
56 | | -class InMemoryDiscoveryStore(AbstractDiscoveryStore): |
| 22 | +class DiscoveryStore: |
57 | 23 | def __init__(self): |
58 | 24 | self.aas_id_to_asset_ids: Dict[model.Identifier, Set[model.SpecificAssetId]] = {} |
59 | 25 | self.asset_id_to_aas_ids: Dict[model.SpecificAssetId, Set[model.Identifier]] = {} |
@@ -93,69 +59,35 @@ def _delete_aas_id_from_specific_asset_ids(self, asset_id: model.SpecificAssetId |
93 | 59 | if asset_id in self.asset_id_to_aas_ids: |
94 | 60 | self.asset_id_to_aas_ids[asset_id].discard(aas_id) |
95 | 61 |
|
96 | | - |
97 | | - |
98 | | - |
99 | | -class MongoDiscoveryStore(AbstractDiscoveryStore): |
100 | | - def __init__(self, |
101 | | - uri: str = "mongodb://localhost:27017", |
102 | | - db_name: str = "basyx", |
103 | | - coll_aas_to_assets: str = "aas_to_assets", |
104 | | - coll_asset_to_aas: str = "asset_to_aas"): |
105 | | - self.client: MongoClient = MongoClient(uri) |
106 | | - self.db = self.client[db_name] |
107 | | - self.coll_aas_to_assets: Collection = self.db[coll_aas_to_assets] |
108 | | - self.coll_asset_to_aas: Collection = self.db[coll_asset_to_aas] |
109 | | - # Create an index for fast asset reverse lookups. |
110 | | - self.coll_asset_to_aas.create_index("_id") |
111 | | - |
112 | | - def get_all_specific_asset_ids_by_aas_id(self, aas_id: model.Identifier) -> List[model.SpecificAssetId]: |
113 | | - key = aas_id |
114 | | - doc = self.coll_aas_to_assets.find_one({"_id": key}) |
115 | | - return doc["asset_ids"] if doc and "asset_ids" in doc else [] |
116 | | - |
117 | | - def add_specific_asset_ids_to_aas(self, aas_id: model.Identifier, asset_ids: List[model.SpecificAssetId]) -> None: |
118 | | - key = aas_id |
119 | | - # Convert each SpecificAssetId using the serialization helper. |
120 | | - serializable_assets = [encoder.default(asset_id) for asset_id in asset_ids] |
121 | | - self.coll_aas_to_assets.update_one( |
122 | | - {"_id": key}, |
123 | | - {"$addToSet": {"asset_ids": {"$each": serializable_assets}}}, |
124 | | - upsert=True |
125 | | - ) |
126 | | - |
127 | | - def delete_specific_asset_ids_by_aas_id(self, aas_id: model.Identifier) -> None: |
128 | | - key = aas_id |
129 | | - self.coll_aas_to_assets.delete_one({"_id": key}) |
130 | | - |
131 | | - def search_aas_ids_by_asset_link(self, asset_link: server_model.AssetLink) -> List[model.Identifier]: |
132 | | - # Query MongoDB for specificAssetIds where 'name' and 'value' match |
133 | | - doc = self.coll_asset_to_aas.find_one({ |
134 | | - "name": asset_link.name, |
135 | | - "value": asset_link.value |
136 | | - }) |
137 | | - return doc["aas_ids"] if doc and "aas_ids" in doc else [] |
138 | | - |
139 | | - def _add_aas_id_to_specific_asset_id(self, asset_id: model.SpecificAssetId, aas_id: model.Identifier) -> None: |
140 | | - asset_key = str(encoder.default(asset_id)) |
141 | | - self.coll_asset_to_aas.update_one( |
142 | | - {"_id": asset_key}, |
143 | | - {"$addToSet": {"aas_ids": aas_id}}, |
144 | | - upsert=True |
145 | | - ) |
146 | | - |
147 | | - def _delete_aas_id_from_specific_asset_ids(self, asset_id: model.SpecificAssetId, aas_id: model.Identifier) -> None: |
148 | | - asset_key = str(encoder.default(asset_id)) |
149 | | - self.coll_asset_to_aas.update_one( |
150 | | - {"_id": asset_key}, |
151 | | - {"$pull": {"aas_ids": aas_id}} |
152 | | - ) |
| 62 | + @classmethod |
| 63 | + def from_file(cls, filename: str) -> "DiscoveryStore": |
| 64 | + """ |
| 65 | + Load the state of the `DiscoveryStore` from a local file. |
| 66 | + The file should be in the format as written by the `self.to_file()` method. |
| 67 | + """ |
| 68 | + with open(filename, "r") as file: |
| 69 | + data = json.load(file, cls=jsonization.ServerAASFromJsonDecoder) |
| 70 | + discovery_store = DiscoveryStore() |
| 71 | + discovery_store.aas_id_to_asset_ids = data["aas_id_to_asset_ids"] |
| 72 | + discovery_store.asset_id_to_aas_ids = data["asset_id_to_aas_ids"] |
| 73 | + return discovery_store |
| 74 | + |
| 75 | + def to_file(self, filename: str) -> None: |
| 76 | + """ |
| 77 | + Write the current state of the `DiscoveryStore` to a local JSON file for persistence. |
| 78 | + """ |
| 79 | + with open(filename, "w") as file: |
| 80 | + data = { |
| 81 | + "aas_id_to_asset_ids": self.aas_id_to_asset_ids, |
| 82 | + "asset_id_to_aas_ids": self.asset_id_to_aas_ids, |
| 83 | + } |
| 84 | + json.dump(data, file, cls=jsonization.ServerAASToJsonEncoder, indent=4) |
153 | 85 |
|
154 | 86 |
|
155 | 87 | class DiscoveryAPI(BaseWSGIApp): |
156 | 88 | def __init__(self, |
157 | | - persistent_store: AbstractDiscoveryStore, base_path: str = "/api/v3.0"): |
158 | | - self.persistent_store: AbstractDiscoveryStore = persistent_store |
| 89 | + persistent_store: DiscoveryStore, base_path: str = "/api/v3.0"): |
| 90 | + self.persistent_store: DiscoveryStore = persistent_store |
159 | 91 | self.url_map = werkzeug.routing.Map([ |
160 | 92 | Submount(base_path, [ |
161 | 93 | Rule("/lookup/shellsByAssetLink", methods=["POST"], |
@@ -208,5 +140,5 @@ def delete_all_asset_links_by_id(self, request: Request, url_args: dict, respons |
208 | 140 | if __name__ == "__main__": |
209 | 141 | from werkzeug.serving import run_simple |
210 | 142 |
|
211 | | - run_simple("localhost", 8084, DiscoveryAPI(InMemoryDiscoveryStore()), |
| 143 | + run_simple("localhost", 8084, DiscoveryAPI(DiscoveryStore()), |
212 | 144 | use_debugger=True, use_reloader=True) |
0 commit comments