Skip to content

Commit 990e03a

Browse files
committed
Fix DiscoveryStore and remove MongoDB dependency
1 parent d2761de commit 990e03a

4 files changed

Lines changed: 44 additions & 111 deletions

File tree

discovery_server/app/main.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
import os
2-
import sys
3-
from server.app.interfaces.discovery import DiscoveryAPI, MongoDiscoveryStore,InMemoryDiscoveryStore
2+
import atexit
43

5-
storage_type = os.getenv("STORAGE_TYPE", "inmemory")
4+
from server.app.interfaces.discovery import DiscoveryAPI, DiscoveryStore
5+
6+
storage_path = os.getenv("storage_path", None)
67
base_path = os.getenv("API_BASE_PATH")
78

89
wsgi_optparams = {}
910

1011
if base_path is not None:
1112
wsgi_optparams["base_path"] = base_path
1213

13-
if storage_type == "inmemory":
14-
application = DiscoveryAPI(InMemoryDiscoveryStore(), **wsgi_optparams)
1514

16-
elif storage_type == "mongodb":
17-
uri = os.getenv("MONGODB_URI", "mongodb://localhost:27017")
18-
dbname = os.getenv("MONGODB_DBNAME", "basyx_registry")
15+
# Load DiscoveryStore from disk, if `storage_path` is set
16+
if storage_path:
17+
discovery_store: DiscoveryStore = DiscoveryStore.from_file(storage_path)
18+
else:
19+
discovery_store = DiscoveryStore()
1920

20-
application = DiscoveryAPI(MongoDiscoveryStore(uri,dbname), **wsgi_optparams)
21+
def persist_store():
22+
if storage_path:
23+
discovery_store.to_file(storage_path)
2124

22-
else:
23-
print(f"STORAGE_TYPE must be either inmemory or mongodb! Current value: {storage_type}",
24-
file=sys.stderr)
25+
atexit.register(persist_store)
2526

27+
application = DiscoveryAPI(discovery_store, **wsgi_optparams)

discovery_server/compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ services:
66
ports:
77
- "8084:80"
88
environment:
9-
- STORAGE_TYPE=inmemory
9+
- storage_path="./discovery_store"

server/app/interfaces/discovery.py

Lines changed: 29 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"""
44

55
import abc
6+
import json
67
from typing import Dict, List, Set, Any
78

89
import werkzeug.exceptions
@@ -15,45 +16,10 @@
1516
from app.util.converters import IdentifierToBase64URLConverter
1617
from app.interfaces.base import BaseWSGIApp, HTTPApiDecoder
1718
from app import model as server_model
18-
from app.adapter.jsonization import ServerAASToJsonEncoder
19+
from app.adapter import jsonization
1920

20-
encoder=ServerAASToJsonEncoder()
2121

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:
5723
def __init__(self):
5824
self.aas_id_to_asset_ids: Dict[model.Identifier, Set[model.SpecificAssetId]] = {}
5925
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
9359
if asset_id in self.asset_id_to_aas_ids:
9460
self.asset_id_to_aas_ids[asset_id].discard(aas_id)
9561

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)
15385

15486

15587
class DiscoveryAPI(BaseWSGIApp):
15688
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
15991
self.url_map = werkzeug.routing.Map([
16092
Submount(base_path, [
16193
Rule("/lookup/shellsByAssetLink", methods=["POST"],
@@ -208,5 +140,5 @@ def delete_all_asset_links_by_id(self, request: Request, url_args: dict, respons
208140
if __name__ == "__main__":
209141
from werkzeug.serving import run_simple
210142

211-
run_simple("localhost", 8084, DiscoveryAPI(InMemoryDiscoveryStore()),
143+
run_simple("localhost", 8084, DiscoveryAPI(DiscoveryStore()),
212144
use_debugger=True, use_reloader=True)

server/pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ requires-python = ">=3.10"
3838
dependencies = [
3939
"urllib3>=1.26,<3",
4040
"Werkzeug>=3.0.3,<4",
41-
"pymongo>=4.16.0",
4241
]
4342

4443
[project.optional-dependencies]

0 commit comments

Comments
 (0)