diff --git a/docs/readme.md b/docs/readme.md index 80888e58..7e20f141 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -11,6 +11,7 @@ - [`nearby(location, [opt])`](nearby.md) – show stations & POIs around - [`radar(north, west, south, east, [opt])`](radar.md) – find all vehicles currently in a certain area - [`reachableFrom(address, [opt])`](reachable-from.md) – get all stations reachable from an address within `n` minutes +- [`serverInfo([opt])`](server-info.md) – fetch meta information from HAFAS ## Migrating from an old `hafas-client` version diff --git a/docs/server-info.md b/docs/server-info.md new file mode 100644 index 00000000..681f311e --- /dev/null +++ b/docs/server-info.md @@ -0,0 +1,33 @@ +# `serverInfo([opt])` + +**Fetches meta information from the HAFAS endpoint.** + +With `opt`, you can override the default options, which look like this: + +```js +{ + language: 'en', // depends on the profile +} +``` + +## Example + +As an example, we're going to use the [SVV profile](../p/svv): + +```js +const createClient = require('hafas-client') +const svvProfile = require('hafas-client/p/svv') + +const client = createClient(svvProfile, 'my-awesome-program') + +console.log(await client.serverInfo()) +``` + +```js +{ + timetableStart: '20200517', + timetableEnd: '20201212', + serverTime: '2020-07-19T21:32:12+02:00', + realtimeDataUpdatedAt: 1595187102, +} +``` diff --git a/index.js b/index.js index 495aa1b2..4faa8902 100644 --- a/index.js +++ b/index.js @@ -468,7 +468,34 @@ const createClient = (profile, userAgent, opt = {}) => { }) } - const client = {departures, arrivals, journeys, locations, stop, nearby} + const serverInfo = async (opt = {}) => { + const {res, common} = await profile.request({profile, opt}, userAgent, { + meth: 'ServerInfo', + req: {} + }) + + const ctx = {profile, opt, common, res} + return { + timetableStart: res.fpB || null, + timetableEnd: res.fpE || null, + serverTime: res.sD && res.sT + ? profile.parseDateTime(ctx, res.sD, res.sT) + : null, + realtimeDataUpdatedAt: res.planrtTS + ? parseInt(res.planrtTS) + : null, + } + } + + const client = { + departures, + arrivals, + journeys, + locations, + stop, + nearby, + serverInfo, + } if (profile.trip) client.trip = trip if (profile.radar) client.radar = radar if (profile.refreshJourney) client.refreshJourney = refreshJourney diff --git a/test/e2e/db.js b/test/e2e/db.js index 9b9390f4..18412537 100644 --- a/test/e2e/db.js +++ b/test/e2e/db.js @@ -26,6 +26,7 @@ const testDeparturesWithoutRelatedStations = require('./lib/departures-without-r const testArrivals = require('./lib/arrivals') const testJourneysWithDetour = require('./lib/journeys-with-detour') const testReachableFrom = require('./lib/reachable-from') +const testServerInfo = require('./lib/server-info') const stations = [] const pStations = new Promise((resolve, reject) => { @@ -451,3 +452,10 @@ test('reachableFrom', async (t) => { }) t.end() }) + +test('serverInfo works', async (t) => { + await testServerInfo({ + test: t, + fetchServerInfo: client.serverInfo, + }) +}) diff --git a/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a b/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a new file mode 100644 index 00000000..f37324ef --- /dev/null +++ b/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a @@ -0,0 +1 @@ +{"ver":"1.20","ext":"VAO.11","lang":"eng","id":"t42agrnmm2g4wm44","err":"OK","cInfo":{"code":"OK","url":"","msg":""},"svcResL":[{"meth":"ServerInfo","err":"OK","res":{"common":{"locL":[],"prodL":[],"polyL":[],"layerL":[{"id":"standard","name":"standard","index":0,"annoCnt":0}],"crdSysL":[{"id":"standard","index":0,"type":"WGS84"}],"opL":[],"remL":[],"txtInstL":[],"icoL":[]},"fpB":"20200517","fpE":"20201212","sD":"20200719","sT":"220453","enc":"UTF-8","planrtTS":"1595189078"}}]} \ No newline at end of file diff --git a/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a.headers b/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a.headers new file mode 100644 index 00000000..5c0f9005 --- /dev/null +++ b/test/e2e/fixtures/08f5be071bd4098b603ebcd9d671b84a.headers @@ -0,0 +1,36 @@ +{ + "statusCode": 200, + "headers": { + "date": "Sun, 19 Jul 2020 20:04:53 GMT", + "server": "Apache", + "content-length": "304", + "keep-alive": "timeout=5, max=13", + "connection": "Keep-Alive", + "content-type": "application/json; charset=utf-8" + }, + "url": "https://fahrplan.salzburg-verkehr.at/bin/mgate.exe", + "time": 312, + "request": { + "method": "POST", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, br, deflate" + ], + "Accept": [ + "application/json" + ], + "user-agent": [ + "public-transport/hafas-client:testdf34c2ec2b3a" + ], + "Content-Length": [ + "182" + ], + "Connection": [ + "close" + ] + } + } +} \ No newline at end of file diff --git a/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc b/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc new file mode 100644 index 00000000..5a06987f --- /dev/null +++ b/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc @@ -0,0 +1 @@ +{"ver":"1.15","ext":"DB.R19.04.a","lang":"eng","id":"pvwu8r74k6wyw644","cInfo":{"code":"OK","url":"","msg":""},"svcResL":[{"meth":"ServerInfo","err":"OK","res":{"common":{"locL":[],"prodL":[],"polyL":[],"layerL":[{"id":"standard","name":"standard","index":0,"annoCnt":0}],"crdSysL":[{"id":"standard","index":0,"type":"WGS84","dim":3}],"opL":[],"remL":[],"icoL":[]},"fpB":"20191215","fpE":"20201212","sD":"20200719","sT":"220419","enc":"ISO-8859-1","planrtTS":"1595188979"}}]} \ No newline at end of file diff --git a/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc.headers b/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc.headers new file mode 100644 index 00000000..2b9d5d83 --- /dev/null +++ b/test/e2e/fixtures/bbc7f8898cbe51f5a85836d62e1abfdc.headers @@ -0,0 +1,35 @@ +{ + "statusCode": 200, + "headers": { + "content-type": "application/json; charset=utf-8", + "date": "Sun, 19 Jul 2020 20:04:19 GMT", + "server": "Apache", + "content-length": "312", + "connection": "Close" + }, + "url": "https://reiseauskunft.bahn.de/bin/mgate.exe?checksum=61043123e067664a035a32152dc11d35", + "time": 286, + "request": { + "method": "POST", + "headers": { + "Content-Type": [ + "application/json" + ], + "Accept-Encoding": [ + "gzip, br, deflate" + ], + "Accept": [ + "application/json" + ], + "user-agent": [ + "public-transpo8bcc44962164rt/hafas-client:test" + ], + "Content-Length": [ + "233" + ], + "Connection": [ + "close" + ] + } + } +} \ No newline at end of file diff --git a/test/e2e/lib/server-info.js b/test/e2e/lib/server-info.js new file mode 100644 index 00000000..13a8b01c --- /dev/null +++ b/test/e2e/lib/server-info.js @@ -0,0 +1,24 @@ +'use strict' + +const testServerInfo = async (cfg) => { + const { + test: t, + fetchServerInfo, + } = cfg + + const info = await fetchServerInfo() + t.ok(info, 'invalid info') + + t.equal(typeof info.timetableStart, 'string', 'invalid info.timetableStart') + t.ok(info.timetableStart, 'invalid info.timetableStart') + t.equal(typeof info.timetableEnd, 'string', 'invalid info.timetableEnd') + t.ok(info.timetableEnd, 'invalid info.timetableEnd') + + t.equal(typeof info.serverTime, 'string', 'invalid info.serverTime') + t.notOk(Number.isNaN(Date.parse(info.serverTime)), 'invalid info.serverTime') + + t.ok(Number.isInteger(info.realtimeDataUpdatedAt), 'invalid info.realtimeDataUpdatedAt') + t.ok(info.realtimeDataUpdatedAt > 0, 'invalid info.realtimeDataUpdatedAt') +} + +module.exports = testServerInfo diff --git a/test/e2e/svv.js b/test/e2e/svv.js index 08235419..814980e1 100644 --- a/test/e2e/svv.js +++ b/test/e2e/svv.js @@ -10,6 +10,7 @@ const testJourneysStationToStation = require('./lib/journeys-station-to-station' const testRefreshJourney = require('./lib/refresh-journey') const testArrivals = require('./lib/arrivals') const testReachableFrom = require('./lib/reachable-from') +const testServerInfo = require('./lib/server-info') const when = createWhen(svvProfile.timezone, svvProfile.locale) @@ -94,3 +95,10 @@ test('reachableFrom', async (t) => { }) t.end() }) + +test('serverInfo works', async (t) => { + await testServerInfo({ + test: t, + fetchServerInfo: client.serverInfo, + }) +}) diff --git a/tools/debug-cli/cli.js b/tools/debug-cli/cli.js index 5f1a2e0b..eb9105a0 100755 --- a/tools/debug-cli/cli.js +++ b/tools/debug-cli/cli.js @@ -38,7 +38,8 @@ const parseArgs = [ ['radar', 0, parseJsObject], ['radar', 1, parseJsObject], ['reachableFrom', 0, parseJsObject], - ['reachableFrom', 1, parseJsObject] + ['reachableFrom', 1, parseJsObject], + ['serverInfo', 0, parseJsObject], ] const argv = mri(process.argv.slice(2))