███████╗ ██████╗ ██████╗ ██████╗ ███████╗██╗ ██╗██╗ ██████╗███████╗███████╗
██╔════╝██╔════╝██╔═══██╗ ██╔══██╗██╔════╝██║ ██║██║██╔════╝██╔════╝██╔════╝
███████╗██║ ██║ ██║ ██║ ██║█████╗ ██║ ██║██║██║ █████╗ ███████╗
╚════██║██║ ██║▄▄ ██║ ██║ ██║██╔══╝ ╚██╗ ██╔╝██║██║ ██╔══╝ ╚════██║
███████║╚██████╗╚██████╔╝ ██████╔╝███████╗ ╚████╔╝ ██║╚██████╗███████╗███████║
╚══════╝ ╚═════╝ ╚══▀▀═╝ ╚═════╝ ╚══════╝ ╚═══╝ ╚═╝ ╚═════╝╚══════╝╚══════╝
███████╗ █████╗ ██╗███╗ ██╗██╗ ██╗
██╔════╝██╔══██╗███║████╗ ██║██║ ██╔╝
█████╗ ███████║╚██║██╔██╗ ██║█████╔╝
██╔══╝ ██╔══██║ ██║██║╚██╗██║██╔═██╗
███████╗██║ ██║ ██║██║ ╚████║██║ ██╗
2026 EA1NK-DxSpider-Ingestor
This repository is designed to run in Docker and is part of the EA1NK-Docker-DxSpider project: https://github.com/ea1nk/EA1NK-Docker-DxSpider
Node.js service that ingests DX spots, enriches them with CTY data from cty_dict.json, stores them in MongoDB, and exposes:
- JWT login endpoint
- Historical query endpoint with filters
- WebSocket stream for real-time spots
- Connects to DXSpider via telnet (
DX_HOST/DX_PORT). - Parses each
DX de ...line into a normalized spot. - Enriches
spotterandspottedcallsigns withlookupCallsignInfofromcallsignLookup.js. - Buffers spots and writes to MongoDB in batches (
BUFFER_LIMIT). - Serves API with Fastify on port
3000.
Environment variables and constants currently used in ingestor.js:
MONGO_URL(default:mongodb://db:27017)DB_NAME(default:rbn_radio)COLLECTION_NAME(default:spots)DX_HOST(default:localhost)DX_PORT(default:7300)CALLSIGN(default placeholder:TU_CALLSIGN)SECRET_KEY(JWT signing key)API_PASSWORD(password for/login)
Returns a JWT token when the password is correct.
Request body:
{
"password": "radio_password"
}Response:
{
"token": "<jwt-token>"
}Use that token in protected endpoints:
Authorization: Bearer <jwt-token>
Returns spot history sorted by timestamp descending.
Query params:
rbn:trueorfalsemode: exact match against storedmodefieldband: exact match (160m,80m,40m, etc.)callsign: regex match onspotterspotterCountry: regex oncty.spotter.data.CountryspottedCountry: regex oncty.spotted.data.Countrycountry: generic country filter (spotter OR spotted)spotterPrefix: prefix match oncty.spotter.matchedCallsignspottedPrefix: prefix match oncty.spotted.matchedCallsignprefix: generic prefix filter (spotter OR spotted)spotterContinent: exact match oncty.spotter.data.Continent(auto uppercased)spottedContinent: exact match oncty.spotted.data.Continent(auto uppercased)continent: generic continent filter (spotter OR spotted)limit: max results (default:100)
Examples:
curl -H "Authorization: Bearer <token>" \
"http://localhost:3000/api/spots?spotterCountry=Spain&limit=50"curl -H "Authorization: Bearer <token>" \
"http://localhost:3000/api/spots?prefix=EA&continent=EU"Real-time stream of parsed/enriched spots.
Each message is a JSON spot document.
Example structure inserted into MongoDB:
{
"spotter": "F4ABC",
"spotted": "EA1XYZ",
"freq": 14074.0,
"band": "20m",
"mode": "FT8",
"snr": 18,
"rbn": true,
"time_z": "1205",
"timestamp": "2026-03-13T12:05:00.000Z",
"cty": {
"spotter": {
"searchedCallsign": "F4ABC",
"matchedCallsign": "F",
"data": {
"Country": "France",
"Prefix": "F",
"ADIF": 227,
"CQZone": 14,
"ITUZone": 27,
"Continent": "EU",
"Latitude": 46,
"Longitude": -2,
"GMTOffset": -1,
"ExactCallsign": false
}
},
"spotted": {
"searchedCallsign": "EA1XYZ",
"matchedCallsign": "EA1",
"data": {
"Country": "Spain"
}
}
}
}- Spots expire automatically after 7 days (TTL index on
timestamp). - There are dedicated indexes for timestamp, RBN, CTY country, CTY prefix, and CTY continent fields.