22
33import json
44import multiprocessing
5+ import os
56import sys
67from datetime import datetime
78from logging import DEBUG , Formatter
3334 system_namespace ,
3435)
3536
36- neurosift_file_registry = list ()
37+ # Dictionary to store file paths with their IDs
38+ neurosift_file_registry = dict ()
3739
3840flask_app = Flask (__name__ )
3941
@@ -71,15 +73,15 @@ def exception_handler(error: Exception) -> Dict[str, str]:
7173 return {"message" : str (error ), "type" : type (error ).__name__ }
7274
7375
74- @flask_app .route ("/files/<int:index >" )
75- def handle_get_file_request (index ) -> Union [str , None ]:
76+ @flask_app .route ("/files/<string:file_id >" )
77+ def handle_get_file_request (file_id ) -> Union [str , None ]:
7678 """
7779 This endpoint is used to access a file that has been registered with the Neurosift service.
7880 """
79- if request .method == "GET" and ( index >= len ( neurosift_file_registry ) or index < 0 ) :
80- raise KeyError (f"Resource at index { index } is not accessible." )
81+ if request .method == "GET" and file_id not in neurosift_file_registry :
82+ raise KeyError (f"File with internal id { file_id } is not accessible." )
8183
82- file_path = neurosift_file_registry [index ]
84+ file_path = neurosift_file_registry [file_id ]
8385 if not isabs (file_path ):
8486 file_path = f"/{ file_path } "
8587
@@ -95,17 +97,27 @@ def handle_file_request(file_path) -> Union[str, None]:
9597 if not file_path .endswith (".nwb" ):
9698 raise ValueError ("This endpoint must be called on an NWB file that ends with '.nwb'!" )
9799
98- # NOTE: It may be faster to look for the file in the registry and return a URL that has already been received
99- # by GUIDE because of caching, but in testing, it seemed that GUIDE/Neurosift was not caching the files.
100- neurosift_file_registry .append (file_path )
101- index = len (neurosift_file_registry ) - 1
102-
103- # files/<index> is the URL that can be used to access the file
104- # NOTE: This endpoint used to be files/<file_path> but file_path would become URL-decoded
105- # by Neurosift which changed + signs to spaces before making the GET request. This broke local reading
106- # of files with + signs in the filename. Other symbols may be affected as well.
107- # This is why we use the safer, but less transparent, files/<index> instead.
108- return request .host_url + "/files/" + str (index )
100+ # Get the last modified time of the file
101+ try :
102+ last_modified = os .path .getmtime (file_path )
103+ last_modified_str = datetime .fromtimestamp (last_modified ).strftime ("%Y%m%d%H%M%S" )
104+ except (OSError , ValueError ):
105+ # If we can't get the last modified time, use current time
106+ last_modified_str = datetime .now ().strftime ("%Y%m%d%H%M%S" )
107+
108+ # Use the number of items in the dictionary as the index
109+ index = len (neurosift_file_registry ) + 1
110+
111+ # Create a file_id that combines the index and last modified date
112+ file_id = f"{ index } _{ last_modified_str } "
113+ neurosift_file_registry [file_id ] = file_path
114+
115+ # files/<file_id> is the URL that can be used to access the file
116+ # NOTE: We use an index joined with the last modified date to ensure uniqueness for
117+ # each request (avoiding Neurosift caching issues) and avoid issues with URL-decoding
118+ # by the external Neurosift app, while providing somewhat meaningful IDs that include
119+ # file modification information.
120+ return request .host_url + "/files/" + file_id
109121
110122
111123@api .route ("/log" )
0 commit comments