-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnode_helper.js
More file actions
13 lines (10 loc) · 5.85 KB
/
node_helper.js
File metadata and controls
13 lines (10 loc) · 5.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
/*! *****************************************************************************
mmm-rnv
Version 1.3.1
This is a departure monitor for the Rhein-Neckar-Verkehr (RNV) public transport network for the MagicMirror² platform.
Please submit bugs at https://github.com/jalibu/MMM-RNV/issues
(c) Julian Dinter,Jan Litzenburger
Licence: MIT
This file is auto-generated. Do not edit.
***************************************************************************** */
"use strict";var t=require("node_helper"),e=require("logger");function n(t){var e=Object.create(null);return t&&Object.keys(t).forEach(function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}),e.default=t,Object.freeze(e)}var r=n(t),s=n(e);module.exports=r.create({start(){this.accessToken=null,this.schedule=[],this.colorCodesMap=new Map,this.failedRequests=0,this.getColorCodes()},async getColorCodes(){try{const t=await fetch("https://rnvopendataportalpublic.blob.core.windows.net/public/openDataPortal/liniengruppen-farben.json"),e=await t.json();this.colorCodesMap=new Map(e.lineGroups.map(t=>[t.id,t]))}catch(t){const e=t instanceof Error?t.message:String(t);s.warn(`Could not request color codes: ${e}`)}},async socketNotificationReceived(t,e){if("RNV_DEPARTURE_REQUEST"===t){const t=e;this.getData(t)}},async getData(t,e=!1){try{if(!this.accessToken)try{this.accessToken=await this.createAccessToken(t)}catch(t){const e=t instanceof Error?t.message:String(t);return(s.error??s.warn)(`Error generating the client: ${e}`),void this.sendSocketNotification("RNV_ERROR_RESPONSE",{type:"ERROR",message:"Error with API authentication."})}const e=new Date(Date.now()+t.walkingTimeMs);s.info(`Request departures for station '${t.stationId}'`);const n="query GetDepartures($stationId: String!, $startTime: String!) {\n station(id: $stationId) {\n hafasID\n longName\n journeys(startTime: $startTime, first: 50) {\n totalCount\n elements {\n ... on Journey {\n line {\n id\n }\n type\n stops(onlyHafasID: $stationId) {\n pole {\n platform {\n type\n label\n barrierFreeType\n }\n }\n destinationLabel\n plannedArrival {\n isoString\n }\n realtimeArrival {\n isoString\n }\n plannedDeparture {\n isoString\n }\n realtimeDeparture {\n isoString\n }\n }\n }\n }\n }\n }\n }",r=[],a=(await this.fetchGraphql(t.clientApiUrl,n,this.accessToken,{stationId:t.stationId,startTime:e.toISOString()})).data.station.journeys.elements.filter(t=>null!==t.stops[0].plannedDeparture.isoString);a.sort((t,e)=>{const n=t.stops[0].plannedDeparture.isoString,r=e.stops[0].plannedDeparture.isoString;return n&&r?n<r?-1:n>r?1:0:0});for(const e of a){const n=e.stops?.[0];if(!n?.plannedDeparture?.isoString)continue;const a=new Date(n.plannedDeparture.isoString);let o=0;try{const t=n.realtimeDeparture?.isoString;if(!t)throw new Error("Missing realtime departure");const e=new Date(t).getTime()-a.getTime();o=Math.round(e/6e4)}catch(t){const e=t instanceof Error?t.message:String(t);s.warn(`Error calculating the delay: ${e}`)}const i=e.line.id.split("-")[1];if(t.excludeLines.includes(i)||t.excludePlatforms.includes(n.pole.platform.label))continue;const c={line:i,destination:n.destinationLabel,departure:a.getTime(),delayInMin:o,platform:n.pole.platform.label,type:e.type,highlighted:t.highlightLines.includes(i),color:this.colorCodesMap.get(i)};if(r.push(c),r.length===t.maxResults)break}this.failedRequests=0,this.sendSocketNotification(`RNV_DATA_RESPONSE_${t.stationId}`,r)}catch(n){const r=n instanceof Error?n.message:String(n),a=n instanceof Error?n.status:void 0;if((401===a||403===a)&&!e)return s.warn(`Authentication error (${a}), resetting token and retrying...`),this.accessToken=null,void this.getData(t,!0);s.warn(`Error fetching the data from the API: ${r}`),this.failedRequests+=1,this.failedRequests>5&&(this.sendSocketNotification("RNV_ERROR_RESPONSE",{type:"ERROR",message:"Error fetching data."}),this.failedRequests=0)}},async createAccessToken(t){const{clientId:e,clientSecret:n,resourceId:r,tenantId:a}=t.credentials,o=new URLSearchParams({grant_type:"client_credentials",client_id:e,client_secret:n,resource:r}),i=await fetch(`https://login.microsoftonline.com/${a}/oauth2/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:o.toString()});if(!i.ok){const t=new Error(`Could not fetch the access token (${i.status} ${i.statusText})`);throw t.status=i.status,t}const{access_token:c}=await i.json();return s.log("Created new RNV API access token"),c},async fetchGraphql(t,e,n,r){const s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json",authorization:n?`Bearer ${n}`:""},body:JSON.stringify({query:e,variables:r})});if(!s.ok){const t=new Error(`GraphQL request failed (${s.status} ${s.statusText})`);throw t.status=s.status,t}const a=await s.json();if(a.errors?.length)throw Error(a.errors.map(t=>t.message).join("; "));return a}});