hkopendata
Version:
Access different Opendata API and data in Hong Kong
155 lines (145 loc) • 4.33 kB
JavaScript
// https://www.nwstbus.com.hk/datagovhk/bus_eta_spi_specifications.pdf
const cmn = require("../../common");
const moment = require("../../moment");
const Coordinate = require("../../_class").Coordinate;
const BASE_URL = "https://rt.data.gov.hk/v1/transport/citybus-nwfb/{type}/{data}";
const ENDPOINT = {
"company": "{company}",
"route": "{company}/{route}",
"route-stop": "{company}/{route}/{dir}",
"stop": "{stop}",
"eta": "{company}/{stop}/{route}",
}
const VALID = {
type: /^(company|route|route-stop|stop|eta)$/
}
const VALID_OPT = {
company: /^(CTB|NWFB)$/,
stop: /^[A-z0-9]{6}$/,
route: /^[A-z0-9]+$/,
dir: /^(inbound|outbound)$/,
}
const PARAMS = {
type: "route"
}
const FIELDS = {
regex: {
"^orig": "origin",
"^dest": "destination",
"^rmk": "remarks"
},
text: {
"co": "companyCode",
"url": "website",
"stop": "_id",
},
latitude: ["lat"],
longitude: ["long"],
};
const SEARCH_CONFIG = {
value: {
type: {
accepted: ["route", "route-stop", "eta", "stop", "company"]
},
dir: {
accepted: ["inbound", "outbound"]
},
},
}
function validateParameters(params) {
params = cmn.ParseSearchFields(params, SEARCH_CONFIG);
let result = cmn.ValidateParameters(params, VALID, VALID_OPT);
if (!result.error && /^(stop|eta)$/.test(params.type) && !("stop" in params)) {
result.error = true;
result.message = "Missing stop";
}
if (!result.error && /^route|^eta$/.test(params.type) && !("route" in params)) {
if (params.type == "route") {
params.route = "";
} else {
result.error = true;
result.message = "Missing route";
}
}
if (!result.error && params.type == "route-stop" && !("dir" in params)) {
result.error = true;
result.message = "Missing dir";
}
if (!result.error && params.type != "stop" && !("company" in params)) {
result.error = true;
result.message = "Missing company";
}
if (!result.error) {
if ("route" in params) params.route = params.route.toUpperCase();
result.data = {
...{
data: ENDPOINT[params.type]
},
...params
}
}
return result;
}
function search(data, opts) {
return new Promise((resolve, reject) => {
let processed = validateParameters({
...PARAMS,
...data
}),
params;
if (processed.error) {
reject(processed);
} else {
params = processed.data;
cmn.APIRequest(cmn.ReplaceURL(BASE_URL, params))
.then((res) => {
resolve(processData(res.data, params.type))
})
.catch((err) => reject(err))
}
})
}
function processData(data, type) {
if (!Array.isArray(data)) data = [data];
let result = [];
data.map(item => {
let temp = {};
item = cmn.RenameFields(item, FIELDS);
for (let key in item) {
let m;
if (m = key.match(/^(.+)_(en|tc|sc)$/)) {
if (!(m[1] in temp)) temp[m[1]] = {};
temp[m[1]][m[2]] = item[key];
} else if (key == "eta") {
temp[key] = moment(item[key]);
} else if (!/data_timestamp|eta_seq/.test(key)) {
temp[key] = item[key];
}
}
if ("coordinate" in temp) {
temp.coordinate = new Coordinate(temp.coordinate)
}
result.push(temp);
})
if (type == "route-stop") {
result = result.sort((a, b) => a.seq - b.seq).map(v => ({
id: v._id,
seq: v.seq,
}));
} else if (type == "eta") {
result = result.sort((a, b) => a.eta.isBefore(b.eta))
.map(v => {
let t = {
eta: v.eta.format("YYYY-MM-DD HH:mm:ss"),
lowFloor: true,
gps: true
};
if ("remarks" in v) {
t.remarks = v.remarks;
}
return t;
});
}
return result;
}
module.exports = search;