Skip to content

Commit b254e13

Browse files
dgarciabrisenoDaniel Garcia Briseno
andauthored
Helpful downloader patches (#489)
* Add ability for downloaders to filter for specific files * Update downloader to re-scan * Add starttime/endtime validation * don't let query magic make starttime go earlier than requested * don't exclusively pick up v0k * Apply suggestion from @dgarciabriseno * Update filter_func for localbrowser.py --------- Co-authored-by: Daniel Garcia Briseno <daniel.garciabriseno@nasa.gov>
1 parent 52c64ef commit b254e13

5 files changed

Lines changed: 35 additions & 25 deletions

File tree

install/helioviewer/hvpull/browser/basebrowser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def get_directories(self, start_time, end_time):
88
"""Gets a list of directories to be queried for the given time range"""
99
return None
1010

11-
def get_files(self, uri, extension):
11+
def get_files(self, uri, extension, filter_func: callable | None = None):
1212
"""Get all the files that end with specified extension at the uri"""
1313
return None
1414

install/helioviewer/hvpull/browser/httpbrowser.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ def read(self, uri):
2222
usock = urllib.request.urlopen(uri)
2323
self.feed(usock.read().decode(usock.headers.get_content_charset()))
2424
usock.close()
25-
25+
2626
return self.urls
27-
27+
2828
def reset(self):
2929
"""Reset state of URLLister"""
3030
HTMLParser.reset(self)
@@ -58,7 +58,7 @@ def read(self, uri):
5858
print (e)
5959

6060
return self.urls
61-
61+
6262
def reset(self):
6363
"""Reset state of URLLister"""
6464
SGMLParser.reset(self)
@@ -73,25 +73,29 @@ class HTTPDataBrowser(BaseDataBrowser):
7373
def __init__(self, server):
7474
BaseDataBrowser.__init__(self, server)
7575
socket.setdefaulttimeout(60)
76-
76+
7777
def get_directories(self, start_date, end_date):
7878
"""Generates a list of remote directories which may be queried
7979
for files corresponding to the requested range. Note that these
8080
directories do not necessarily exist on the remote server."""
8181
# filter(lambda url: url.endswith("/"), self._query(location))
8282
return self.server.compute_directories(start_date, end_date)
8383

84-
def get_files(self, location, extension):
84+
def get_files(self, location, extension, filter_func: callable | None = None):
8585
"""Get all the files that end with specified extension at the uri"""
8686
files = None
8787
num_retries = 0
88-
88+
8989
# Get a list of the files at the remote location, if it exists
9090
# To avoid spending too much time, we will timeout after a short time
9191
# and retry up to 10 times.
9292
while files is None and num_retries <= 10:
9393
try:
94+
# Only grab files with the matching file extension
9495
files = filter(lambda url: url.endswith("." + extension), self._query(location))
96+
# If there is a user-defined filter function, use that to only get those specific files.
97+
if filter_func is not None:
98+
files = filter(filter_func, files)
9599
except IOError as e:
96100
if isinstance(e.strerror, socket.error):
97101
# if server is unreachable, raise an exception
@@ -105,10 +109,10 @@ def get_files(self, location, extension):
105109
files = []
106110

107111
return files
108-
112+
109113
def _query(self, location):
110114
"""Get a list of files and folders at the specified remote location"""
111-
# query the remote location for the list of files and subdirectories
115+
# query the remote location for the list of files and subdirectories.
112116

113117
if (sys.version_info >= (3, 0)):
114118
url_lister = URLLister()
@@ -121,4 +125,4 @@ def _query(self, location):
121125
urls = filter(lambda url: url[0] != "/" and url[0] != "?", result)
122126

123127
return [os.path.join(location, url) for url in urls]
124-
128+

install/helioviewer/hvpull/browser/localbrowser.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def get_directories(self, start_date, end_date):
1414
"""Get a list of directories at the passed uri"""
1515
return self.server.compute_directories(start_date, end_date)
1616

17-
def get_files(self, location, extension):
17+
def get_files(self, location, extension, filter_func: callable | None = None):
1818
"""Get all the files that end with specified extension at the uri"""
1919

2020
# ensure the location exists
@@ -26,4 +26,7 @@ def get_files(self, location, extension):
2626
)
2727
files = [os.path.join(full_path, f) for f in filenames]
2828

29+
if filter_func is not None:
30+
files = list(filter(filter_func, files))
31+
2932
return files

install/helioviewer/hvpull/net/daemon.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def start(self, starttime=None, endtime=None, backfill=None):
174174
# get a list of files available
175175
# self.oldest_timestamp gets set by query() during the first run
176176
# before the main loop.
177-
self.query(starttime, now)
177+
self.query(self.oldest_timestamp, now)
178178

179179
self.sleep()
180180

@@ -201,6 +201,8 @@ def query(self, starttime, endtime):
201201
if any new files have appeared since the first execution. This continues
202202
until no new files are found (for xxx minutes?)
203203
"""
204+
if (starttime > endtime):
205+
raise ValueError(f"Start Time {starttime} is ahead of End Time {endtime}. No files would be downloaded.")
204206
urls = []
205207

206208
fmt = '%Y-%m-%d %H:%M:%S'
@@ -241,6 +243,7 @@ def query(self, starttime, endtime):
241243
try:
242244
# Filter by time range
243245
filtered = self._filter_files_by_time(url_list, starttime, endtime)
246+
# Filter to only download new files that have not already been downloaded previously.
244247
filtered = list(filter(self._filter_new, filtered))
245248
except mysqld.OperationalError:
246249
# MySQL has gone away -- try again in 5s
@@ -322,11 +325,13 @@ def query(self, starttime, endtime):
322325
if self.servers[0].name in ['LMSAL2']:
323326
new_urls.append(extra_filtered)
324327
if len(extra_filtered) > 0:
325-
self.oldest_timestamp = self._get_oldest_image(extra_filtered)
328+
# Using max(starttime, ...) so oldest_timestamp never goes earlier than the initial requested starttime
329+
self.oldest_timestamp = max(starttime, self._get_oldest_image(extra_filtered))
326330
else:
327331
new_urls.append(filtered)
328332
if len(filtered) > 0:
329-
self.oldest_timestamp = self._get_oldest_image(filtered)
333+
# Using max(starttime, ...) so oldest_timestamp never goes earlier than the initial requested starttime
334+
self.oldest_timestamp = max(starttime, self._get_oldest_image(filtered))
330335

331336
# check disk space
332337
if not self.sent_diskspace_warning:
@@ -421,7 +426,7 @@ def query_server(self, browser, starttime, endtime):
421426
return []
422427

423428
try:
424-
matches = browser.get_files(directory, "jp2")
429+
matches = browser.get_files(directory, "jp2", browser.server.filter)
425430

426431
files.extend(matches)
427432
except NetworkError:

install/helioviewer/hvpull/servers/__init__.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,13 @@ def get_dates(self, starttime, endtime):
6868

6969
return dates
7070

71-
def get_file_regex(self):
72-
"""Returns a regex which described the expected format of filenames on
73-
the server"""
74-
return self.filename_regex
71+
def filter(self, file: str) -> bool:
72+
"""
73+
Returns True if the file should be downloaded, otherwise False.
74+
This may be overridden by specific Data Servers to only download
75+
specific files from the upstream directory
76+
"""
77+
return True
7578

7679
def get_measurements(self, nicknames, dates):
7780
"""Get a list of all the URIs down to the measurement"""
@@ -85,7 +88,7 @@ def get_datetime_from_file(self, filename):
8588
return get_datetime_from_file(filename)
8689

8790

88-
class DataServerPauseDelayDefinesDefaultStartTime:
91+
class DataServerPauseDelayDefinesDefaultStartTime(DataServer):
8992
"""Class for interacting with data servers. In this class the
9093
pause defines the default start time. If real time is UTC, then
9194
the default start time is UTC - pause minutes."""
@@ -126,11 +129,6 @@ def get_dates(self, starttime, endtime):
126129

127130
return dates
128131

129-
def get_file_regex(self):
130-
"""Returns a regex which described the expected format of filenames on
131-
the server"""
132-
return self.filename_regex
133-
134132
def get_measurements(self, nicknames, dates):
135133
"""Get a list of all the URIs down to the measurement"""
136134
return None

0 commit comments

Comments
 (0)