devendergarg14 commited on
Commit
57114a8
·
verified ·
1 Parent(s): 6541ee1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -28
app.py CHANGED
@@ -19,26 +19,27 @@ HISTORY_DURATION_SECONDS = 60 * 60
19
  # Structure: { "id": "uuid", "url": "string", "status": "pending/ok/error/checking",
20
  # "ip": "string", "responseTime": float_ms, "lastChecked": "iso_string_utc",
21
  # "history": [{"timestamp": float_unix_ts_seconds, "status": "ok/error"}],
22
- # "userId": "string_user_uuid", # ADDED: To associate URL with a user
23
  # "_thread": threading.Thread_object, "_stop_event": threading.Event_object }
24
  monitored_urls_store = {}
25
- lock = threading.Lock()
26
 
27
  # --- Helper Functions ---
28
  def save_data_to_json():
29
- with lock: # Ensure lock is acquired before calling if called externally
30
- serializable_data = {}
31
- for url_id, data in monitored_urls_store.items():
32
- s_data = data.copy()
33
- s_data.pop("_thread", None)
34
- s_data.pop("_stop_event", None)
35
- serializable_data[url_id] = s_data
36
- try:
37
- with open(DATA_FILE, 'w') as f:
38
- json.dump(serializable_data, f, indent=2)
39
- print(f"Data saved to {DATA_FILE}")
40
- except IOError as e:
41
- print(f"Error saving data to {DATA_FILE}: {e}")
 
42
 
43
  def load_data_from_json():
44
  global monitored_urls_store
@@ -57,7 +58,7 @@ def load_data_from_json():
57
  data_item.setdefault('responseTime', None)
58
  data_item.setdefault('lastChecked', None)
59
  data_item.setdefault('history', data_item.get('history', []))
60
- data_item.setdefault('userId', None) # ADDED: Handle old data without userId
61
  temp_store[current_id] = data_item
62
 
63
  with lock:
@@ -75,8 +76,6 @@ def load_data_from_json():
75
 
76
  url_ids_to_start_monitoring = []
77
  with lock:
78
- # We don't know the user context here, so all threads for loaded URLs are started.
79
- # The GET endpoint will filter by user.
80
  url_ids_to_start_monitoring = list(monitored_urls_store.keys())
81
 
82
  for url_id in url_ids_to_start_monitoring:
@@ -170,7 +169,7 @@ def execute_url_check(url_id_to_check):
170
  live_url_data['history'] = current_history_list
171
  prune_url_history(live_url_data)
172
 
173
- save_data_to_json()
174
  print(f"Finished check for {live_url_data['url']}: {final_check_status}, {http_response_time_ms} ms")
175
 
176
  def pinger_thread_function(url_id_param, stop_event_param):
@@ -224,13 +223,12 @@ def serve_index():
224
  def get_all_urls_for_user():
225
  user_id = request.headers.get('X-User-ID')
226
  if not user_id:
227
- # Return empty list if no user ID is provided, or could be 400 error
228
  return jsonify([]), 200
229
 
230
  with lock:
231
  response_list = []
232
  for data_item in monitored_urls_store.values():
233
- if data_item.get('userId') == user_id: # Filter by userId
234
  display_item = data_item.copy()
235
  display_item.pop("_thread", None)
236
  display_item.pop("_stop_event", None)
@@ -263,7 +261,6 @@ def add_new_url_for_user():
263
  with lock:
264
  normalized_new_url = input_url.rstrip('/').lower()
265
  for existing_url_data in monitored_urls_store.values():
266
- # Check for duplicates only for the current user
267
  if existing_url_data.get('userId') == user_id and \
268
  existing_url_data['url'].rstrip('/').lower() == normalized_new_url:
269
  return jsonify({"error": "URL already monitored by you"}), 409
@@ -274,12 +271,12 @@ def add_new_url_for_user():
274
  url_entry_to_add = {
275
  "id": new_url_id, "url": input_url, "status": 'pending',
276
  "ip": resolved_ip, "responseTime": None, "lastChecked": None, "history": [],
277
- "userId": user_id # Associate with the user
278
  }
279
 
280
  response_payload = url_entry_to_add.copy()
281
  monitored_urls_store[new_url_id] = url_entry_to_add
282
- save_data_to_json()
283
 
284
  start_url_monitoring_thread(new_url_id)
285
  return jsonify(response_payload), 201
@@ -295,14 +292,12 @@ def delete_existing_url_for_user(target_url_id):
295
  if target_url_id in monitored_urls_store:
296
  url_entry_to_check = monitored_urls_store[target_url_id]
297
 
298
- # Check if the URL belongs to the requesting user
299
  if url_entry_to_check.get('userId') != user_id:
300
- # Do not reveal existence of URL; treat as if not found for this user
301
  return jsonify({"error": "URL not found or permission denied"}), 404
302
 
303
- stop_url_monitoring_thread(target_url_id)
304
  removed_url_entry = monitored_urls_store.pop(target_url_id)
305
- save_data_to_json()
306
 
307
  response_data = removed_url_entry.copy()
308
  response_data.pop("_thread", None)
 
19
  # Structure: { "id": "uuid", "url": "string", "status": "pending/ok/error/checking",
20
  # "ip": "string", "responseTime": float_ms, "lastChecked": "iso_string_utc",
21
  # "history": [{"timestamp": float_unix_ts_seconds, "status": "ok/error"}],
22
+ # "userId": "string_user_uuid",
23
  # "_thread": threading.Thread_object, "_stop_event": threading.Event_object }
24
  monitored_urls_store = {}
25
+ lock = threading.Lock() # Non-reentrant lock
26
 
27
  # --- Helper Functions ---
28
  def save_data_to_json():
29
+ # This function must be called with 'lock' acquired
30
+ # REMOVED 'with lock:' from here as callers already acquire it.
31
+ serializable_data = {}
32
+ for url_id, data in monitored_urls_store.items():
33
+ s_data = data.copy()
34
+ s_data.pop("_thread", None)
35
+ s_data.pop("_stop_event", None)
36
+ serializable_data[url_id] = s_data
37
+ try:
38
+ with open(DATA_FILE, 'w') as f:
39
+ json.dump(serializable_data, f, indent=2)
40
+ print(f"Data saved to {DATA_FILE}")
41
+ except IOError as e:
42
+ print(f"Error saving data to {DATA_FILE}: {e}")
43
 
44
  def load_data_from_json():
45
  global monitored_urls_store
 
58
  data_item.setdefault('responseTime', None)
59
  data_item.setdefault('lastChecked', None)
60
  data_item.setdefault('history', data_item.get('history', []))
61
+ data_item.setdefault('userId', None)
62
  temp_store[current_id] = data_item
63
 
64
  with lock:
 
76
 
77
  url_ids_to_start_monitoring = []
78
  with lock:
 
 
79
  url_ids_to_start_monitoring = list(monitored_urls_store.keys())
80
 
81
  for url_id in url_ids_to_start_monitoring:
 
169
  live_url_data['history'] = current_history_list
170
  prune_url_history(live_url_data)
171
 
172
+ save_data_to_json() # Called while lock is held
173
  print(f"Finished check for {live_url_data['url']}: {final_check_status}, {http_response_time_ms} ms")
174
 
175
  def pinger_thread_function(url_id_param, stop_event_param):
 
223
  def get_all_urls_for_user():
224
  user_id = request.headers.get('X-User-ID')
225
  if not user_id:
 
226
  return jsonify([]), 200
227
 
228
  with lock:
229
  response_list = []
230
  for data_item in monitored_urls_store.values():
231
+ if data_item.get('userId') == user_id:
232
  display_item = data_item.copy()
233
  display_item.pop("_thread", None)
234
  display_item.pop("_stop_event", None)
 
261
  with lock:
262
  normalized_new_url = input_url.rstrip('/').lower()
263
  for existing_url_data in monitored_urls_store.values():
 
264
  if existing_url_data.get('userId') == user_id and \
265
  existing_url_data['url'].rstrip('/').lower() == normalized_new_url:
266
  return jsonify({"error": "URL already monitored by you"}), 409
 
271
  url_entry_to_add = {
272
  "id": new_url_id, "url": input_url, "status": 'pending',
273
  "ip": resolved_ip, "responseTime": None, "lastChecked": None, "history": [],
274
+ "userId": user_id
275
  }
276
 
277
  response_payload = url_entry_to_add.copy()
278
  monitored_urls_store[new_url_id] = url_entry_to_add
279
+ save_data_to_json() # Called while lock is held
280
 
281
  start_url_monitoring_thread(new_url_id)
282
  return jsonify(response_payload), 201
 
292
  if target_url_id in monitored_urls_store:
293
  url_entry_to_check = monitored_urls_store[target_url_id]
294
 
 
295
  if url_entry_to_check.get('userId') != user_id:
 
296
  return jsonify({"error": "URL not found or permission denied"}), 404
297
 
298
+ stop_url_monitoring_thread(target_url_id) # Must be called with lock held
299
  removed_url_entry = monitored_urls_store.pop(target_url_id)
300
+ save_data_to_json() # Called while lock is held
301
 
302
  response_data = removed_url_entry.copy()
303
  response_data.pop("_thread", None)