Skip to content

Commit 0bb84a2

Browse files
committed
pre commit clean up
1 parent 9be7fa3 commit 0bb84a2

8 files changed

Lines changed: 103 additions & 111 deletions

File tree

gateway/config/settings/base.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,8 @@ def __get_random_token(length: int) -> str:
481481
# -------------------------------------------------------------------------------
482482
# django-rest-framework - https://www.django-rest-framework.org/api-guide/settings/
483483
# Visualization streaming throttle (waterfall_slices_stream). Override with
484-
# VIS_STREAM_THROTTLE_RATE (e.g. "300/min", "900/min") in .env for heavier use or local dev.
484+
# VIS_STREAM_THROTTLE_RATE (e.g. "300/min", "900/min") in .env for heavier
485+
# use or local dev.
485486
VIS_STREAM_THROTTLE_RATE: str = env.str("VIS_STREAM_THROTTLE_RATE", "300/min")
486487

487488
REST_FRAMEWORK: dict[str, str | tuple[str, ...] | dict[str, str]] = {
@@ -654,9 +655,10 @@ def _get_brand_image_url() -> str | None:
654655
default=guess_max_web_download_size(),
655656
)
656657

657-
# Testing override: report a fake large number of slices for waterfall visualizations when set.
658-
# Useful for UI/scale testing. Set WATERFALL_TEST_TOTAL_SLICES to an integer (e.g. 100000000)
659-
# and optionally WATERFALL_TEST_MIN_CAPTURE_SLICES to only apply the override for captures
658+
# Testing override: report a fake large number of slices for waterfall
659+
# visualizations when set. Useful for UI/scale testing. Set
660+
# WATERFALL_TEST_TOTAL_SLICES to an integer (e.g. 100000000) and optionally
661+
# WATERFALL_TEST_MIN_CAPTURE_SLICES to only apply the override for captures
660662
# with at least that many real slices (default: 1_000_000).
661663
WATERFALL_TEST_TOTAL_SLICES: int = env.int("WATERFALL_TEST_TOTAL_SLICES", default=0)
662664
WATERFALL_TEST_MIN_CAPTURE_SLICES: int = env.int(

gateway/sds_gateway/api_methods/views/capture_endpoints.py

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from typing import cast
88

99
import ijson
10-
1110
from django.db import transaction
1211
from django.db.models import QuerySet
1312
from django.http import FileResponse
@@ -19,7 +18,6 @@
1918
from drf_spectacular.utils import OpenApiResponse
2019
from drf_spectacular.utils import extend_schema
2120
from loguru import logger as log
22-
from django.conf import settings
2321
from opensearchpy import exceptions as os_exceptions
2422
from rest_framework import status
2523
from rest_framework import viewsets
@@ -54,6 +52,7 @@
5452
serialize_capture_or_composite,
5553
)
5654
from sds_gateway.api_methods.tasks import start_capture_post_processing
55+
from sds_gateway.api_methods.throttling import VisStreamThrottle
5756
from sds_gateway.api_methods.utils.asset_access_control import (
5857
user_has_access_to_capture,
5958
)
@@ -66,14 +65,15 @@
6665
from sds_gateway.visualizations.models import ProcessingStatus
6766
from sds_gateway.visualizations.processing.utils import reconstruct_drf_files
6867
from sds_gateway.visualizations.processing.waterfall import FFT_SIZE
69-
from sds_gateway.visualizations.processing.waterfall import get_waterfall_power_bounds
7068
from sds_gateway.visualizations.processing.waterfall import SAMPLES_PER_SLICE
71-
from sds_gateway.api_methods.throttling import VisStreamThrottle
7269
from sds_gateway.visualizations.processing.waterfall import compute_slices_on_demand
70+
from sds_gateway.visualizations.processing.waterfall import get_waterfall_power_bounds
7371
from sds_gateway.visualizations.serializers import PostProcessedDataSerializer
7472

7573
MAX_CAPTURE_NAME_LENGTH = 255 # Maximum length for capture names
76-
MAX_SLICE_BATCH_SIZE = 300 # Max slices per request (larger = fewer calls when fast-forwarding)
74+
MAX_SLICE_BATCH_SIZE = (
75+
300 # Max slices per request (larger = fewer calls when fast-forwarding)
76+
)
7777

7878

7979
def _validate_slice_indices(
@@ -163,9 +163,8 @@ def _extract_waterfall_slice_range(
163163
if total_slices_from_metadata is not None:
164164
total_slices = total_slices_from_metadata
165165
if start_index >= total_slices:
166-
raise ValueError(
167-
f"start_index ({start_index}) exceeds total slices ({total_slices})"
168-
)
166+
msg = f"start_index ({start_index}) exceeds total slices ({total_slices})"
167+
raise ValueError(msg)
169168
end_index = min(end_index, total_slices)
170169
else:
171170
# One pass to count array length (no list storage)
@@ -178,20 +177,17 @@ def _extract_waterfall_slice_range(
178177
raise
179178
total_slices = count
180179
if start_index >= total_slices:
181-
raise ValueError(
182-
f"start_index ({start_index}) exceeds total slices ({total_slices})"
183-
)
180+
msg = f"start_index ({start_index}) exceeds total slices ({total_slices})"
181+
raise ValueError(msg)
184182
end_index = min(end_index, total_slices)
185183
file_handle.seek(0)
186184

187185
requested_slices: list[Any] = []
188-
current = 0
189-
for item in ijson.items(file_handle, "item"):
186+
for current, item in enumerate(ijson.items(file_handle, "item")):
190187
if current >= end_index:
191188
break
192189
if current >= start_index:
193190
requested_slices.append(item)
194-
current += 1
195191

196192
return requested_slices, total_slices
197193

@@ -409,13 +405,18 @@ def _get_processed_data_for_capture(
409405

410406
if not processed_data:
411407
hint = ""
412-
if capture.capture_type == CaptureType.DigitalRF and processing_type == "waterfall":
413-
hint = " For DigitalRF captures, streaming mode may work without preprocessed data; otherwise run post-processing to generate waterfall data."
408+
if (
409+
capture.capture_type == CaptureType.DigitalRF
410+
and processing_type == "waterfall"
411+
):
412+
hint = (
413+
" For DigitalRF captures, streaming mode may work without "
414+
"preprocessed data; otherwise run post-processing to generate "
415+
"waterfall data."
416+
)
414417
else:
415418
hint = " Run post-processing to generate this data."
416-
msg = (
417-
f"No completed {processing_type} data found for this capture.{hint}"
418-
)
419+
msg = f"No completed {processing_type} data found for this capture.{hint}"
419420
raise Http404(msg)
420421

421422
if not processed_data.data_file:
@@ -530,7 +531,7 @@ def _validate_create_request(
530531
def _handle_capture_creation_errors(
531532
self, capture: Capture, error: Exception
532533
) -> Response:
533-
"""Handle errors during capture creation. Transaction auto-rolls back on error."""
534+
"""Handle capture creation errors. Transaction auto-rolls back on error."""
534535
if isinstance(error, UnknownIndexError):
535536
user_msg = f"Unknown index: '{error}'. Try recreating this capture."
536537
server_msg = (
@@ -1178,9 +1179,7 @@ def download_post_processed_data(
11781179
),
11791180
)
11801181
@action(detail=True, methods=["get"])
1181-
def waterfall_slices( # noqa: PLR0911
1182-
self, request: Request, pk: str | None = None
1183-
) -> Response:
1182+
def waterfall_slices(self, request: Request, pk: str | None = None) -> Response:
11841183
"""Get waterfall slices by index range for streaming."""
11851184
# Get query parameters
11861185
processing_type = request.query_params.get("processing_type", "waterfall")
@@ -1298,8 +1297,15 @@ def get_post_processed_metadata(
12981297

12991298
if not processed_data:
13001299
hint = ""
1301-
if capture.capture_type == CaptureType.DigitalRF and processing_type == "waterfall":
1302-
hint = " For DigitalRF captures, streaming mode may work without preprocessed data; otherwise run post-processing to generate waterfall data."
1300+
if (
1301+
capture.capture_type == CaptureType.DigitalRF
1302+
and processing_type == "waterfall"
1303+
):
1304+
hint = (
1305+
" For DigitalRF captures, streaming mode may work without "
1306+
"preprocessed data; otherwise run post-processing to generate "
1307+
"waterfall data."
1308+
)
13031309
else:
13041310
hint = " Run post-processing to generate this data."
13051311
return Response(
@@ -1331,9 +1337,9 @@ def get_post_processed_metadata(
13311337
required=False,
13321338
default=False,
13331339
description=(
1334-
"If true, compute power_bounds (min/max dB) by sampling DRF data, "
1335-
"which may trigger MinIO download and processing. Omit or false for "
1336-
"fast metadata-only response."
1340+
"If true, compute power_bounds (min/max dB) by sampling DRF "
1341+
"data, which may trigger MinIO download and processing. Omit "
1342+
"or false for fast metadata-only response."
13371343
),
13381344
),
13391345
],
@@ -1411,7 +1417,7 @@ def waterfall_metadata_stream(
14111417
status=status.HTTP_400_BAD_REQUEST,
14121418
)
14131419

1414-
# Bounds are in seconds (from DRF metadata: sample_index / samples_per_second)
1420+
# Bounds in seconds (DRF metadata: sample_index / samples_per_second)
14151421
duration_seconds = end_bound - start_bound
14161422
total_samples = int(duration_seconds * samples_per_second)
14171423
log.debug(
@@ -1446,9 +1452,7 @@ def waterfall_metadata_stream(
14461452
).lower() in ("true", "1", "yes")
14471453
if include_power_bounds:
14481454
try:
1449-
capture_files = get_capture_files(
1450-
capture, include_deleted=False
1451-
)
1455+
capture_files = get_capture_files(capture, include_deleted=False)
14521456
if capture_files.exists():
14531457
dummy_temp_path = Path(tempfile.gettempdir()) / "unused"
14541458
drf_path = reconstruct_drf_files(

gateway/sds_gateway/static/js/visualizations/waterfall/WaterfallRenderer.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,7 @@ class WaterfallRenderer {
148148
this.drawWaterfallSlice(slice.data, y, sliceHeight, this.canvas.width);
149149
} else if (slice?._gap) {
150150
// Known data gap (backend had no data for this range)
151-
this.drawGapPlaceholder(
152-
sliceIndex,
153-
y,
154-
sliceHeight,
155-
this.canvas.width,
156-
);
151+
this.drawGapPlaceholder(sliceIndex, y, sliceHeight, this.canvas.width);
157152
} else {
158153
// Draw loading placeholder for missing slice
159154
this.drawLoadingPlaceholder(

gateway/sds_gateway/static/js/visualizations/waterfall/WaterfallSliceCache.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,13 @@ class WaterfallSliceCache {
2626
if (!Number.isFinite(idx) || idx < 0) {
2727
return null;
2828
}
29-
sliceIndex = idx;
30-
if (this.knownGaps.has(sliceIndex)) {
29+
if (this.knownGaps.has(idx)) {
3130
return { _gap: true };
3231
}
33-
if (this.cache.has(sliceIndex)) {
32+
if (this.cache.has(idx)) {
3433
// Update access order (move to end = most recently used)
35-
this._updateAccessOrder(sliceIndex);
36-
return this.cache.get(sliceIndex);
34+
this._updateAccessOrder(idx);
35+
return this.cache.get(idx);
3736
}
3837
return null;
3938
}
@@ -84,12 +83,11 @@ class WaterfallSliceCache {
8483
if (!Number.isFinite(idx) || idx < 0) {
8584
return;
8685
}
87-
sliceIndex = idx;
8886

8987
// If already cached, just update access order
90-
if (this.cache.has(sliceIndex)) {
91-
this._updateAccessOrder(sliceIndex);
92-
this.cache.set(sliceIndex, sliceData);
88+
if (this.cache.has(idx)) {
89+
this._updateAccessOrder(idx);
90+
this.cache.set(idx, sliceData);
9391
return;
9492
}
9593

@@ -99,8 +97,8 @@ class WaterfallSliceCache {
9997
}
10098

10199
// Add to cache
102-
this.cache.set(sliceIndex, sliceData);
103-
this.accessOrder.push(sliceIndex);
100+
this.cache.set(idx, sliceData);
101+
this.accessOrder.push(idx);
104102
}
105103

106104
/**

gateway/sds_gateway/static/js/visualizations/waterfall/WaterfallSliceLoader.js

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ class WaterfallSliceLoader {
154154
// boundaries so concurrent 1-slice requests (periodogram, etc.) share one API call.
155155
let fetchStart = startIndex;
156156
let fetchEnd = endIndex;
157-
if (this.useStreamingEndpoint && fetchEnd - fetchStart < MIN_STREAMING_BATCH) {
157+
if (
158+
this.useStreamingEndpoint &&
159+
fetchEnd - fetchStart < MIN_STREAMING_BATCH
160+
) {
158161
fetchStart =
159162
Math.floor(startIndex / MIN_STREAMING_BATCH) * MIN_STREAMING_BATCH;
160163
fetchEnd = fetchStart + MIN_STREAMING_BATCH;
@@ -207,11 +210,8 @@ class WaterfallSliceLoader {
207210
// Notify callback. When slices.length === 0 we pass the requested range (fetchStart, fetchEnd)
208211
// so the visible-window overlap check in onSlicesLoaded succeeds and the UI re-renders with "No data".
209212
const callbackEnd =
210-
slices.length > 0
211-
? actualStartIndex + slices.length
212-
: fetchEnd;
213-
const callbackStart =
214-
slices.length > 0 ? actualStartIndex : fetchStart;
213+
slices.length > 0 ? actualStartIndex + slices.length : fetchEnd;
214+
const callbackStart = slices.length > 0 ? actualStartIndex : fetchStart;
215215
if (this.onSliceLoaded) {
216216
this.onSliceLoaded(slices, callbackStart, callbackEnd);
217217
}
@@ -282,14 +282,11 @@ class WaterfallSliceLoader {
282282
errorData.error || `HTTP ${response.status}: ${response.statusText}`;
283283

284284
// Retry on 429 (rate limit) using Retry-After or backoff
285-
if (
286-
response.status === 429 &&
287-
retryCount < this.maxRetries
288-
) {
285+
if (response.status === 429 && retryCount < this.maxRetries) {
289286
const retryAfterHeader = response.headers.get("Retry-After");
290287
const waitSeconds = retryAfterHeader
291-
? Math.min(parseInt(retryAfterHeader, 10) || 60, 60)
292-
: this.retryDelay * 2 ** retryCount / 1000;
288+
? Math.min(Number.parseInt(retryAfterHeader, 10) || 60, 60)
289+
: (this.retryDelay * 2 ** retryCount) / 1000;
293290
await this._sleep(waitSeconds * 1000);
294291
return this._fetchSlicesWithRetry(
295292
startIndex,

gateway/sds_gateway/static/js/visualizations/waterfall/WaterfallVisualization.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,7 @@ class WaterfallVisualization {
159159
const now = performance.now();
160160
const throttleElapsed =
161161
now - this._lastPeriodogramTime >= this._periodogramThrottleMs;
162-
if (
163-
sliceInCache ||
164-
!this.controls?.isPlaying ||
165-
throttleElapsed
166-
) {
162+
if (sliceInCache || !this.controls?.isPlaying || throttleElapsed) {
167163
if (!sliceInCache) this._lastPeriodogramTime = now;
168164
this.renderPeriodogram();
169165
}
@@ -673,10 +669,7 @@ class WaterfallVisualization {
673669
try {
674670
const metadataData = await metadataResponse.json();
675671
const total = metadataData?.metadata?.total_slices;
676-
if (
677-
typeof total === "number" &&
678-
total >= LARGE_CAPTURE_THRESHOLD
679-
) {
672+
if (typeof total === "number" && total >= LARGE_CAPTURE_THRESHOLD) {
680673
const streamingSuccess = await this.tryLoadStreamingMode();
681674
if (streamingSuccess) return;
682675
}
@@ -1262,9 +1255,7 @@ class WaterfallVisualization {
12621255
this.currentSliceIndex < endIndex
12631256
) {
12641257
const now = performance.now();
1265-
if (
1266-
now - this._lastPeriodogramTime >= this._periodogramThrottleMs
1267-
) {
1258+
if (now - this._lastPeriodogramTime >= this._periodogramThrottleMs) {
12681259
this._lastPeriodogramTime = now;
12691260
this.renderPeriodogram();
12701261
} else if (!this._pendingPeriodogramRender) {

0 commit comments

Comments
 (0)