Expand description
Serves archived Parquet sample files as streamed CSV exports.
The streamer publishes LabJack samples to the local NATS JetStream, and the
archiver writes them to Parquet files under
<PARQUET_DIR>/assetNNN/YYYY-MM-DD/chNN/*.parquet. This binary reads those files
back for a requested asset, channel list and time range, applies the calibration
stored in each file’s metadata, and sends the rows as CSV with the columns
timestamp,channel,raw_value,calibrated_value,calibration_id. A request that
names noise filters for a channel (ExportRequest::filters) gets a sixth
column, filtered_value, computed by the zero-phase pipeline in filters over
the range plus margins; the archive itself is never changed.
It runs in one of two modes that share the request format (ExportRequest)
and the scanning logic:
- Worker mode (the default and the normal edge-box setup) subscribes to the core
NATS subject
<NATS_SUBJECT>.<site>.<box>.<source_id>.export.requestand answers each request on its reply subject. Every reply message carries the headerAvena-Export-Framenaming the frame:meta, then one or morechunkframes with raw CSV bytes (about 512 KiB each, the last one smaller), thensummaryandcomplete. Failures produce anerrorframe. Seeprocess_nats_requestandNatsCsvStreamerfor the exact payloads, the ack-subject backpressure and the cancel message a client can send there. - Direct mode serves the same export over a WebSocket at
ws://<EXPORTER_ADDR>/export. The client sends one JSON request as a text message and receives the same frames as JSON text messages, with CSV chunks (about 128 KiB) as binary messages. Seeprocess_socket.
§Configuration
EXPORTER_MODE-worker, ordirect(aliaslocal). Trimmed and case-insensitive; any other value is a startup error. Default:worker.EXPORTER_ADDR- TCP listen address for the WebSocket server in direct mode. Default:0.0.0.0:9001.PARQUET_DIR- Root of the Parquet archive. A missing directory only logs a warning at startup. Default:parquet.NATS_SERVERS- Worker mode. Comma-separated NATS server URLs. Default:nats://127.0.0.1:4222.NATS_CREDS_FILE- Worker mode. NATS credentials file. Default:apt.creds.NATS_SUBJECT- Worker mode. Root token of the request subject. Default:avenars.SITE_ID- Worker mode. Site token of the request subject. Default:unknown-site.EXPORT_BOX_ID- Worker mode. Box token of the request subject; falls back toBOX_ID. One of the two is required in worker mode.BOX_ID- Worker mode. Used whenEXPORT_BOX_IDis unset.SOURCE_ID- Worker mode. Source token of the request subject. When it is unset or empty the token falls back toLABJACK_NAME, thenasset<ASSET_NUMBER>, thenunknown-source, the same order the streamer and the webapp use (seesubjects::archive_export_request_subject).LABJACK_NAME- Worker mode. The source’s LabJack name, used only whenSOURCE_IDis not set.ASSET_NUMBER- Worker mode. The source’s asset number, used only when neitherSOURCE_IDnorLABJACK_NAMEis set.SOURCE_TYPE- Worker mode. Read and passed to the subject builder, which currently ignores it. Default:labjack.
§Design
- Worker mode exists so the webapp needs only its existing WebSocket connection
to central NATS. The browser publishes a request with a reply inbox, the NATS
leaf routes it to the worker on the box that holds the Parquet files, and the
CSV comes back the same way. Direct mode requires the client to reach the box
itself. Core NATS has no flow control, so the worker waits for client acks
on
ack_subjectevery 8 chunks instead of flooding a slow browser. - Each Parquet row group stores min/max statistics for the timestamp column.
read_matching_rowsskips row groups whose range lies outside the request without decoding them, and reads the two columns with typed readers rather than building a row object per sample. - The archive can hold more than one copy of a sample: an archiver fed the same
JetStream messages again writes them into new part files, sometimes with other
window boundaries or another calibration. Each channel-day’s files are grouped
by overlapping time spans (
overlapping_file_groups), found from the footer statistics. A file that overlaps nothing is read in one pass, as before. Overlapping files are read together in five-minute slices so memory stays bounded by one slice rather than a day. Either way the rows are sorted by time and each exact(timestamp, raw value)pair is sent once (read_merged_rows); a clean file in time order comes out exactly as stored. Rows with the same timestamp but different values are all kept. - Each export runs as a three-stage pipeline (
spawn_csv): a reader thread lists and decodes the files (and runs the filters) one merge slice ahead, a CSV thread formats the rows into chunks, and the request’s async task sends the chunks and handles acks. Decoding, formatting and sending overlap, and no file reading or formatting blocks the async runtime; the bytes and their order are the same as reading, formatting and sending one after another. - Formatting a row is the main CPU cost of an export, so
CsvRowWriteravoids most of it while writing the same bytes aswriteln!: rows are sent in time order, soRfc3339Formatterbuilds the date and time up to the second with chrono once per second and writes only the fractional digits per row (identical text to chrono’sto_rfc3339), andValueTextCachereuses theraw,calibratedtext of raw values seen before, which with a 16-bit converter is nearly every row.
Modules§
- calibration 🔒
- Calibration formulas stored with archived channel data.
- filters 🔒
- Noise filters applied to exported data (never to the archive).
- nats_
config 🔒 - Shared NATS server-list and JetStream context helpers.
- subjects 🔒
- NATS subject builders for LabJack live data and archive exports.
Structs§
- AppState 🔒
- State shared by the Axum WebSocket handler and the NATS worker tasks.
- CsvBuilder 🔒
- Formats an export’s rows into CSV chunks on its CSV thread; see
spawn_csv. - CsvJob 🔒
- What an export reads, handed to its CSV thread (
spawn_csv). - CsvRow
Writer 🔒 - Writes export CSV rows into a chunk buffer.
- CsvStreamer 🔒
- CSV streamer for direct WebSocket exports.
- Error
Frame 🔒 - Direct-mode error frame sent when an export request cannot be served.
- Export
Cancelled 🔒 - Error returned when the client cancels a worker-mode export.
- Export
Filters 🔒 - Filters asked for by an export request, per channel.
- Export
Request 🔒 - Export request accepted by both WebSocket and NATS worker modes.
- File
Span 🔒 - Timestamp span of one archived part file, read from its footer.
- Filter
Input 🔒Row - One row of a filtered export.
- Filtered
Channel 🔒Rows - Reads one channel over the export range plus lead-in and settling margins and runs it through the zero-phase filter pipeline, one merge slice at a time.
- Matched
File 🔒 - Rows of one Parquet file that fall inside an export range.
- Merged
Rows 🔒 - Rows of one or more files, sorted by time with exact duplicates removed.
- Meta
Frame 🔒 - Direct-mode metadata frame sent before CSV chunks.
- Nats
CsvStreamer 🔒 - CSV streamer for NATS worker exports.
- Rfc3339
Formatter 🔒 - Formats timestamps exactly like chrono’s
to_rfc3339, faster. - Summary
Frame 🔒 - Direct-mode summary frame sent after all CSV chunks are delivered.
- Value
Slot 🔒 - One cached
raw,calibratedtext ofValueTextCache. - Value
Text 🔒Cache - Remembers the
raw_value,calibrated_valuetext of recently written raw values. - WebSocket
Sink 🔒 - WebSocket implementation of
ExportSink.
Enums§
- Export
Format 🔒 - Requested export format, written in JSON as
"csv"or"parquet". - Exporter
Mode 🔒 - Exporter runtime mode.
- Filtered
Column 🔒 - Value column of a CSV row after
calibration_id, if the export has one. - Read
Item 🔒 - Rows of an export in CSV order, from
read_rowstoCsvBuilder.
Constants§
- CHUNK_
SLACK 🔒 - Bytes reserved in a chunk buffer beyond its chunk size, so the row that crosses the size normally fits without the buffer being reallocated and copied.
- CSV_
CHUNKS_ 🔒AHEAD - Finished chunks the CSV thread may hold ready while the previous ones are sent.
- CSV_
HEADER 🔒 - CSV header of an export without filters.
- CSV_
HEADER_ 🔒FILTERED - CSV header of an export with filters.
- DEFAULT_
EXPORTER_ 🔒ADDR - WebSocket listen address used in direct mode when
EXPORTER_ADDRis unset. - DEFAULT_
EXPORTER_ 🔒MODE - Runtime mode used when
EXPORTER_MODEis unset. - EXPORT_
FRAME_ 🔒CANCEL - Frame name a client sends on its
ack_subjectto stop an export. - EXPORT_
FRAME_ 🔒CHUNK - Frame name for a CSV payload chunk (raw bytes, not JSON).
- EXPORT_
FRAME_ 🔒COMPLETE - Frame name marking the end of a successful export.
- EXPORT_
FRAME_ 🔒ERROR - Frame name for request validation or processing errors (
message). - EXPORT_
FRAME_ 🔒HEADER - NATS header whose value names the frame type of each worker-mode reply message.
- EXPORT_
FRAME_ 🔒META - Frame name for the metadata frame (
fileName,contentType) sent before any CSV. - EXPORT_
FRAME_ 🔒SUMMARY - Frame name for the final byte count and missing-channel list.
- FILTER_
LEAD_ 🔒IN_ S - Seconds read before the export range so the templates have learnt the interference by the first exported row (their memory).
- MERGE_
SLICE_ 🔒NS - Length of the time slices in which overlapping files are merged (300 s).
- VALUE_
CACHE_ 🔒BYPASS - Rows a
ValueTextCacheformats directly after a window with fewer than one hit in four, before it tries the table again. - VALUE_
CACHE_ 🔒SLOTS - Number of slots in
ValueTextCache; a power of two. - VALUE_
CACHE_ 🔒TEXT - Longest
raw,calibratedtext aValueTextCacheslot holds, bytes. - VALUE_
CACHE_ 🔒WINDOW - Lookups over which
ValueTextCachemeasures its hit rate.
Traits§
- Export
Sink 🔒 - Transport abstraction for framed export responses.
Functions§
- calibration_
preference 🔒 - Returns how strongly a copy’s calibration is preferred when copies collide.
- connect_
nats_ 🔒from_ env - Connects to NATS using the standard credentials and server environment.
- date_
range 🔒 - Builds an inclusive list of UTC dates covered by an export request.
- datetime_
to_ 🔒unix_ ns - Converts an instant to Unix nanoseconds, clamping outside the i64 range.
- default_
format 🔒 - Default export format used when a request omits
format. - file_
time_ 🔒span - Finds the earliest and latest timestamp in one archived file.
- handle_
ws 🔒 - Upgrades an HTTP request into a WebSocket export session.
- is_
cancel_ 🔒message - Tells whether a message on the ack subject is a cancel request.
- main 🔒
- Starts the exporter in direct WebSocket mode or NATS worker mode.
- merge_
slices 🔒 - Splits the export range covered by one file group into merge slices.
- overlapping_
file_ 🔒groups - Lists one channel-day folder and groups its files by overlapping time spans.
- parse_
range 🔒 - Parses an RFC 3339 start/end range into UTC instants.
- process_
nats_ 🔒request - Validates and serves one NATS export request payload.
- process_
socket 🔒 - Handles one direct-mode WebSocket export session.
- publish_
nats_ 🔒json - Publishes a JSON export control frame on a NATS reply subject.
- push_
fraction 🔒 - Appends
.andvalueas exactlywidthdecimal digits, zero-padded, likewrite!(out, ".{value:0width$}")for avaluebelow10^width. - read_
calibration_ 🔒from_ metadata - Reads calibration metadata written by the archiver from a Parquet file.
- read_
column 🔒 - Reads every value of one required column in a row group.
- read_
export_ 🔒request - Reads the initial JSON export request from a WebSocket.
- read_
matching_ 🔒rows - Reads the rows of one archived file whose timestamps fall in
[start_ns, end_ns]. - read_
merged_ 🔒rows - Reads one slice of a file group, merged into time order without duplicates.
- read_
rows 🔒 - Reads the rows of every channel of an export, in order, and hands them over.
- row_
group_ 🔒may_ match - Returns whether a row group’s timestamp statistics overlap
[start_ns, end_ns]. - run_
worker 🔒 - Runs exporter worker mode by subscribing to one NATS request subject.
- same_
formula 🔒 - Tells whether two formulas give the same result for every input: same kind and coefficients with the same bits.
- sanitize_
token 🔒 - Normalizes namespace text into a subject-safe token.
- serve_
export_ 🔒request - Validates a request and streams its CSV response through an export sink.
- sort_
and_ 🔒drop_ duplicates - Sorts rows by timestamp and removes exact duplicates.
- spawn_
csv 🔒 - Starts building an export’s CSV on a blocking thread.
- worker_
box_ 🔒id_ from_ env - Reads the box identifier required to construct the worker request subject.
- write_
values 🔒 - Appends
{raw},{calibrated}toout,calibratedbeingspecapplied toraw.
Type Aliases§
- Calibration
Table 🔒 - Calibrations and CSV calibration ids of a filtered channel, each once, in the order first seen. Shared with the CSV thread, which reads a batch’s rows with it.