feat: working data download and indexing

This commit is contained in:
2018-11-01 16:57:10 -07:00
parent 2067fd63ca
commit 571e6dfd75
12 changed files with 289 additions and 22 deletions

80
src/lib/data-source.mjs Normal file
View File

@@ -0,0 +1,80 @@
import logger from './logger.mjs';
import { BadRequest } from './es-errors.mjs';
import zeroPad from './zero-pad.mjs';
const doctype = 'doc';
// helper for time-based indices
function getIndexName(index) {
const d = new Date();
const [year, month, day] = [
d.getFullYear(),
zeroPad(d.getMonth() + 1, 2),
zeroPad(d.getDate(), 2),
];
return `${index}-${year}.${month}.${day}`;
}
export async function createIndex(client, index) {
const realIndex = getIndexName(index);
return client.indices
.create({
index: realIndex,
body: {
settings: {},
mappings: {
[doctype]: {
properties: {
transponder: { type: 'keyword' },
callsign: { type: 'keyword' },
origin_country: { type: 'keyword' },
time_position: { type: 'date' },
last_contact: { type: 'date' },
location: { type: 'geo_point' },
baro_altitude: { type: 'float' },
geo_altitude: { type: 'float' },
on_ground: { type: 'boolean' },
velocity: { type: 'float' },
vertical_rate: { type: 'float' },
squawk: { type: 'keyword' },
spi: { type: 'boolean' },
position_source: { type: 'keyword' },
},
},
},
},
})
.then(res => {
logger.debug(`Index created: ${res.index}`);
return res.index;
})
.catch(err => {
// check for existing index
if (err instanceof BadRequest) {
logger.debug(`Index exists: ${realIndex}`);
return client.indices.get({ index: realIndex }).then(() => realIndex);
}
throw err;
});
}
export async function createDocument(client, index, body) {
client.index({
index,
type: doctype,
body,
});
}
export async function bulkInsert(client, index, docs) {
const body = docs.reduce((collection, doc) => {
collection.push({ index: { _index: index, _type: doctype } });
collection.push(doc);
return collection;
}, []);
client.bulk({
body,
});
}

3
src/lib/es-errors.mjs Normal file
View File

@@ -0,0 +1,3 @@
import elasticsearch from 'elasticsearch';
export const { BadRequest, NotFound, Forbidden, Conflict } = elasticsearch.errors;

13
src/lib/fetch.mjs Normal file
View File

@@ -0,0 +1,13 @@
import axios from 'axios';
const api = 'https://opensky-network.org/api';
export default axios.create({
baseURL: api,
timeout: 3000,
responseType: 'json',
headers: {
'X-Custom-Header': 'foobar',
'Content-Type': 'application/json; charset=utf-8',
},
});

6
src/lib/get-data.mjs Normal file
View File

@@ -0,0 +1,6 @@
import fetch from './fetch.mjs';
export default async function getData() {
const res = await fetch.get('/states/all');
return res.data.states;
}

35
src/lib/logger.mjs Normal file
View File

@@ -0,0 +1,35 @@
/* eslint no-console: 0 */
import zeroPad from './zero-pad.mjs';
const getTimestamp = () => {
const d = new Date();
return `${[d.getFullYear(), zeroPad(d.getMonth() + 1, 2), zeroPad(d.getDate(), 2)].join('/')} ${[
zeroPad(d.getHours(), 2),
zeroPad(d.getMinutes(), 2),
zeroPad(d.getSeconds(), 2),
].join(':')}`;
};
const wrapMessage = msg => `[${getTimestamp()}]: ${msg.map(m => JSON.stringify(m)).join(' ')}`;
const logger = {
log(...args) {
console.log(wrapMessage(args));
},
warn(...args) {
console.warn(wrapMessage(args));
},
error(...args) {
if (args[0] instanceof Error) {
console.error(getTimestamp(), args[0].stack);
return;
}
console.error(wrapMessage(args));
},
debug(...args) {
if (!process.env.DEBUG) return;
console.log(wrapMessage(args));
},
};
export default logger;

9
src/lib/zero-pad.mjs Normal file
View File

@@ -0,0 +1,9 @@
export default function zeroPad(str, len) {
let output = `${str}`;
if (!len || len <= output.length) return str;
while (output.length < len) {
output = `0${output}`;
}
return output;
}