1- """
2- Licensed under the Apache License, Version 2.0 (the "License");
3- you may not use this file except in compliance with the License.
4- You may obtain a copy of the License at
5-
6- http://www.apache.org/licenses/LICENSE-2.0
7-
8- Unless required by applicable law or agreed to in writing, software
9- distributed under the License is distributed on an "AS IS" BASIS,
10- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11- See the License for the specific language governing permissions and
12- limitations under the License.
13-
14-
15- Author: Ibrahim Hroob
16- Email: ibrahim.hroub7@gmail.com
17- """
18-
191from pymongo import MongoClient
202from datetime import datetime , timezone
213from bson import ObjectId
224
5+ # NEW
6+ try :
7+ import numpy as np
8+ except Exception :
9+ np = None
10+
11+
2312class DatabaseMgr :
2413 """
2514 A class to manage database operations for robot session.
26-
27- Attributes:
28- client (MongoClient): The MongoDB client.
29- db (Database): The MongoDB database.
30- sessions_collection (Collection): The MongoDB collection for sessions.
31- session_id (ObjectId): The ID of the current session.
3215 """
3316
3417 def __init__ (self , database_name = 'robot_incidents' , host = 'localhost' , port = 27017 ):
35- """
36- Initializes the DatabaseMgr with a given database name, host, and port.
37-
38- Args:
39- database_name (str): The name of the database to connect to.
40- host (str): The hostname or IP address of the MongoDB server.
41- port (int): The port of the MongoDB server.
42- """
4318 self .client = MongoClient (
4419 f'mongodb://{ host } :{ port } /' ,
45- # serverSelectionTimeoutMS=-1, # Disable server selection timeout
46- # socketTimeoutMS=-1, # Disable socket timeout
47- connectTimeoutMS = None # Disable connection timeout
48- )
20+ connectTimeoutMS = None
21+ )
4922 self .db = self .client [database_name ]
5023 self .sessions_collection = self .db ['sessions' ]
5124 self .session_id = None
5225
26+ # NEW
27+ def _bson_safe (self , obj ):
28+ """Recursively convert non-BSON types (notably numpy) into Mongo-friendly types."""
29+ if np is not None :
30+ # numpy arrays -> list
31+ if isinstance (obj , np .ndarray ):
32+ return obj .tolist ()
33+ # numpy scalar -> python scalar
34+ if isinstance (obj , np .generic ):
35+ return obj .item ()
36+
37+ if isinstance (obj , dict ):
38+ return {k : self ._bson_safe (v ) for k , v in obj .items ()}
39+
40+ if isinstance (obj , (list , tuple )):
41+ return [self ._bson_safe (v ) for v in obj ]
42+
43+ return obj
44+
5345 def init_session (self , env_variables , aoc_repos_info ):
54- """
55- Initializes a new session with the given environmental variables.
56-
57- Args:
58- **env_variables: Arbitrary keyword arguments containing session information.
59- Expected keys include 'robot_name', 'farm_name', 'field_name', 'application',
60- and 'scenario_name'.
61- """
6246 session_start = datetime .now (tz = timezone .utc )
6347 session_document = {
6448 "session_start_time" : session_start ,
@@ -67,107 +51,65 @@ def init_session(self, env_variables, aoc_repos_info):
6751 "field_name" : env_variables ['field_name' ],
6852 "application" : env_variables ['application' ],
6953 "scenario_name" : env_variables ['scenario_name' ],
70- "aoc_repos_info" : aoc_repos_info ,
71- "mdbi" : None ,
54+ "aoc_repos_info" : aoc_repos_info ,
55+ "mdbi" : None ,
7256 "incidents" : 0 ,
7357 "distance" : 0 ,
7458 "autonomous_distance" : 0 ,
75- "collision_incidents" : 0 , # NEW
59+ "collision_incidents" : 0 ,
7660 "events" : []
7761 }
62+
63+ # NEW: sanitize (in case aoc_repos_info contains numpy types)
64+ session_document = self ._bson_safe (session_document )
65+
7866 result = self .sessions_collection .insert_one (session_document )
7967 self .session_id = result .inserted_id
8068
8169 def add_event (self , event ):
82- """
83- Adds an event to the current session.
84-
85- Args:
86- event (dict): The event to add.
70+ # NEW: sanitize event before writing
71+ event = self ._bson_safe (event )
8772
88- Returns:
89- bool: True if the event was added successfully, False otherwise.
90- """
9173 result = self .sessions_collection .update_one (
9274 {"_id" : ObjectId (self .session_id )},
9375 {"$addToSet" : {"events" : event }}
9476 )
9577 return result .modified_count > 0
9678
9779 def update_incidents (self , incidents ):
98- """
99- Updates the incidents value of the current session.
100-
101- Args:
102- incidents (int): The new incidents value.
103-
104- Returns:
105- bool: True if the incidents was updated successfully, False otherwise.
106- """
80+ incidents = self ._bson_safe (incidents ) # harmless; keeps pattern consistent
10781 result = self .sessions_collection .update_one (
10882 {"_id" : ObjectId (self .session_id )},
10983 {"$set" : {"incidents" : incidents }}
11084 )
11185 return result .modified_count > 0
11286
11387 def update_distance (self , distance ):
114- """
115- Updates the distance value of the current session.
116-
117- Args:
118- distance (float): The new distance value.
119-
120- Returns:
121- bool: True if the distance was updated successfully, False otherwise.
122- """
88+ distance = self ._bson_safe (distance )
12389 result = self .sessions_collection .update_one (
12490 {"_id" : ObjectId (self .session_id )},
12591 {"$set" : {"distance" : distance }}
12692 )
12793 return result .modified_count > 0
12894
12995 def update_autonomous_distance (self , autonomous_distance ):
130- """
131- Updates the autonomous_distance value of the current session.
132-
133- Args:
134- autonomous_distance (float): The new autonomous_distance value.
135-
136- Returns:
137- bool: True if the autonomous_distance was updated successfully, False otherwise.
138- """
96+ autonomous_distance = self ._bson_safe (autonomous_distance )
13997 result = self .sessions_collection .update_one (
14098 {"_id" : ObjectId (self .session_id )},
14199 {"$set" : {"autonomous_distance" : autonomous_distance }}
142100 )
143101 return result .modified_count > 0
144-
145- def update_mdbi (self , mdbi ):
146- """
147- Updates the mdbi value of the current session.
148102
149- Args:
150- mdbi (float): The new mdbi value.
151-
152- Returns:
153- bool: True if the mdbi was updated successfully, False otherwise.
154- """
103+ def update_mdbi (self , mdbi ):
104+ mdbi = self ._bson_safe (mdbi )
155105 result = self .sessions_collection .update_one (
156106 {"_id" : ObjectId (self .session_id )},
157107 {"$set" : {"mdbi" : mdbi }}
158108 )
159109 return result .modified_count > 0
160-
161- def update_collision_incidents (self , collision_incidents ):
162- """
163- Updates the collision_incidents value of the current session.
164-
165- Args:
166- collision_incidents (int): The new collision incidents value.
167110
168- Returns:
169- bool: True if the value was updated successfully, False otherwise.
170- """
111+ def update_collision_incidents (self , collision_incidents ):
112+ collision_incidents = self ._bson_safe (collision_incidents )
171113 result = self .sessions_collection .update_one (
172114 {"_id" : ObjectId (self .session_id )},
173115 {"$set" : {"collision_incidents" : collision_incidents }}
0 commit comments