@@ -99,6 +99,74 @@ def get_file(self, file_id):
9999 logger .warning (f"Status Code { response .status_code } ; Message: { response .content } " )
100100 return None
101101
102+
103+ def put_file (self , file_id , file_content ):
104+ logger .info (f"Uploading file to OPDM local storage with ID -> { file_id } " )
105+
106+ url = f"{ WEBDAV_SERVER_PUT .rstrip ('/' )} /{ str (file_id ).lstrip ('/' )} "
107+ auth = (WEBDAV_USERNAME , WEBDAV_PASSWORD )
108+
109+ headers = {"Content-Type" : "application/octet-stream" }
110+
111+ # Normalize data + content-length to avoid chunked transfer
112+ data = None
113+ try :
114+ if isinstance (file_content , (bytes , bytearray )):
115+ data = file_content
116+ headers ["Content-Length" ] = str (len (data ))
117+ elif hasattr (file_content , "read" ):
118+ # It's a file-like object
119+ try :
120+ file_content .seek (0 )
121+ except Exception :
122+ pass
123+ data = file_content
124+ # Best-effort content-length from fileno(); falls back to reading into memory
125+ size = None
126+ if hasattr (file_content , "fileno" ):
127+ try :
128+ import os
129+ size = os .fstat (file_content .fileno ()).st_size
130+ except Exception :
131+ size = None
132+ if size is None :
133+ # As a last resort, read to bytes to ensure a Content-Length
134+ buf = file_content .read ()
135+ if hasattr (file_content , "seek" ):
136+ try :
137+ file_content .seek (0 )
138+ except Exception :
139+ pass
140+ data = buf
141+ headers ["Content-Length" ] = str (len (buf ))
142+ else :
143+ headers ["Content-Length" ] = str (size )
144+ else :
145+ raise TypeError ("file_content must be bytes/bytearray or a file-like object" )
146+ except Exception as prep_err :
147+ logger .error (f"Failed preparing payload for { file_id } : { prep_err } " )
148+ return False
149+
150+ try :
151+ response = requests .put (
152+ url ,
153+ data = data ,
154+ headers = headers ,
155+ auth = auth ,
156+ verify = False , # consider True + proper CA in production
157+ timeout = 120 ,
158+ )
159+ if response .status_code in (200 , 201 , 204 ):
160+ logger .info (f"Successfully uploaded file with ID -> { file_id } " )
161+ return True
162+ else :
163+ logger .warning (f"Failed to upload file with ID -> { file_id } " )
164+ logger .warning (f"Status Code { response .status_code } ; Message: { response .content } " )
165+ return False
166+ except Exception as e :
167+ logger .error (f"Exception while uploading file with ID -> { file_id } : { e } " )
168+ return False
169+
102170 def get_latest_models_and_download (self , time_horizon , scenario_date , tso = None ):
103171
104172 meta = {'pmd:scenarioDate' : scenario_date , 'pmd:timeHorizon' : time_horizon }
0 commit comments