Skip to content
Snippets Groups Projects
Commit 9b2c2320 authored by Kasalehlia's avatar Kasalehlia
Browse files

Merge branch 'master' into 'master'

future! (as in not EOL) node, flex design

See merge request !4
parents d9db3ca6 92a6a8c3
No related branches found
No related tags found
1 merge request!4future! (as in not EOL) node, flex design
{
"presets": ["es2015"]
}
public/
module.exports = {
extends: 'marudor/noReact',
env: {
node: true,
},
globals: {
pad: false,
DOW: false,
},
rules: {
'header/header': 0,
}
}
*.swp
npm-debug.log
node_modules
modules
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(8000);
app.use(express.static(__dirname + '/public'));
var instanceClients = [];
io.on('connection', function (socket) {
socket.on('ident', function (client) {
if (instanceClients.indexOf(client) === -1) {
instanceClients.push(client);
socket.emit('meta', 'reload');
}
})
});
function endsWith(str, suffix) {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
}
// for reasons
DOW = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
pad = function (n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
var normalizedPath = require("path").join(__dirname, "modules");
require("fs").readdirSync(normalizedPath).forEach(function(file) {
if (endsWith(file,'.js')) {
try {
require("./modules/" + file)(io);
console.log(file+" loaded");
} catch (e) {
console.log("Error loading "+file);
console.log(e);
}
}
});
require('./modules/main.js');
var httpreq = require('httpreq');
var Mustache = require('mustache');
var URL = 'https://stratum0.org/status/status.json';
var TEMPLATES = {};
require('fs').readFile('modules/brand/template.mustache', 'utf-8', function (err, data) {
TEMPLATES.template = data;
});
require('fs').readFile('modules/brand/status.mustache', 'utf-8', function (err, data) {
TEMPLATES.status = data;
});
var status = {};
function renderStatus(sock, everything) {
var sendInner = function () {
status.random = ''+Math.random();
sock.emit('brand.status', Mustache.render(TEMPLATES.status, status));
}
if (everything) {
sock.emit('brand', Mustache.render(TEMPLATES.template, {}));
setTimeout(sendInner, 3000);
} else {
sendInner();
}
}
function fetchStatus(cb) {
httpreq.get(URL, function (err, res) {
var state = JSON.parse(res.body).state;
cb(state);
});
}
module.exports = function (io) {
var firstTime = true;
function update() {
fetchStatus(function (state) {
if (status.lastchange != state.lastchange) {
var d = new Date(state.lastchange*1000);
state.since = DOW[d.getDay()]+', '+pad(d.getHours(),2)+':'
+pad(d.getMinutes(),2);
status = state;
renderStatus(io);
}
if (firstTime && status) {
io.on('connection', function (sock) {
renderStatus(sock, true);
});
renderStatus(io, true);
firstTime = false;
} else {
renderStatus(io, false);
}
});
}
setInterval(update, 2*60*1000); //every 2 minutes
update();
}
var fs = require('fs');
var Mustache = require('mustache');
var XML = require('pixl-xml');
var httpreq = require('httpreq');
/// CONFIG
var CITY = 'Braunschweig';
var STOPS = ['Ludwigstraße','Hamburger Straße'];
var ENTRIES = 6;
/// VARS
var CACHED = [];
var TEMPLATES = {};
fs.readFile('modules/bus/outer.mustache', 'utf-8', function (err, data) {
TEMPLATES.outer = data;
});
fs.readFile('modules/bus/inner.mustache', 'utf-8', function (err, data) {
TEMPLATES.inner = data;
});
/// FUNS
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
function fetchData(stop, cb) {
var url = "http://62.154.206.87/efaws2/default/XML_DM_REQUEST?sessionID=0&requestID=0&language=de&useRealtime=1&coordOutputFormat=WGS84[DD.ddddd]&locationServerActive=1&mode=direct&dmLineSelectionAll=1&depType=STOPEVENTS&useAllStops=1&command=null&type_dm=stop&name_dm="+CITY+' '+stop+"&mId=efa_rc2"
httpreq.get(url, {binary: true}, function (err, res) {
try {
cb(XML.parse(res.body));
} catch(e) {
}
});
}
function renderLine(line) {
var image = '';
if (line.charAt(0) == "M") {
image = 'metro.svg';
line = line.substr(1);
} else if (line.length < 3) {
image = 'tram.svg';
} else {
image = 'bus.svg';
}
return '<img src="/modules/bus/'+image+'"> '+line;
}
function getData(stop, count, cb) {
fetchData(stop, function (data) {
var deps = data.itdDepartureMonitorRequest.itdDepartureList.itdDeparture;
cb(deps.slice(0, count).map(function (dep) {
return {
line: dep.itdServingLine.symbol,
renderedLine: renderLine(dep.itdServingLine.symbol),
dir: dep.itdServingLine.direction.replace(CITY, '').trim(),
platform: dep.platform,
mean: dep.itdServingLine.itdNoTrain.name,
day: pad(dep.itdDateTime.itdDate.day,2),
month: pad(dep.itdDateTime.itdDate.month,2),
hour: pad(dep.itdDateTime.itdTime.hour,2),
minute: pad(dep.itdDateTime.itdTime.minute,2)
};
}));
});
}
function update(io, allStopsDoneCb) {
var done = [];
var context = [];
var innerGetData = function (stop, i) {
var ns = normalizeStop(stop);
getData(stop, ENTRIES, function (deps) {
try {
context[i] = {stop: stop, normalizedStop: ns, deps: deps};
io.emit('bus.'+ns, Mustache.render(TEMPLATES.inner, context[i]));
if (done.indexOf(stop) === -1) {
done.push(stop);
if (done.length === STOPS.length) {
allStopsDoneCb();
}
}
CACHED = context;
} catch (e) {console.log(e);}
// calculate when to update next
var d = new Date();
var hour = d.getHours();
var minute = d.getMinutes();
var depHour = deps[0].hour < hour ? deps[0].hour+24 : deps[0].hour;
var diff = (depHour-hour)*60 + (deps[0].minute-minute);
setTimeout(function () {
innerGetData(stop, i);
}, (diff * 60 + (60-d.getSeconds()) % 60) * 1000);
});
}
STOPS.forEach(function (stop, i) {
innerGetData(stop, i);
});
}
function normalizeStop(stop) {
return stop.replace(/[^a-zA-Z0-9_]/g,'');
}
module.exports = function (io) {
update(io, function () {
var pushToClient = function (sock) {
sock.emit('bus', Mustache.render(TEMPLATES.outer, CACHED));
setTimeout(function () {
for (var i in CACHED) {
sock.emit('bus.'+CACHED[i].normalizedStop,
Mustache.render(TEMPLATES.inner, CACHED[i]));
}
}, 3000); //wait a second to let the client process the outlets
};
io.on('connect', pushToClient);
pushToClient(io);
});
}
var httpreq = require('httpreq');
var ical = require('ical.js');
var Mustache = require('mustache');
var time = require('time');
var URL = 'https://stratum0.org/kalender/termine.ics';
var TEMPLATE = '';
require('fs').readFile('modules/calendar/template.mustache', 'utf-8', function (err, data) {
TEMPLATE = data;
});
var CALENDAR;
var TZOFFSET = new time.Date().getTimezoneOffset()*60;
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
function parseDate(s) {
var i = parseInt;
if (s.indexOf('T') > -1) {
return new Date(i(s.substr(0,4)), i(s.substr(4,2))-1, i(s.substr(6,2)),
i(s.substr(9,2)), i(s.substr(11,2)), i(s.substr(13,2)));
} else {
return new Date(i(s.substr(0,4)), i(s.substr(4,2))-1, i(s.substr(6,2)));
}
}
function getData(count, cb) {
httpreq.get(URL, function (err, res) {
var ics = res.body.replace(/[0-9]{8}T[0-9]{6}/g, '$&Z');
var cal = new ical.Component(ical.parse(ics));
var rawEvents = cal.getAllSubcomponents('vevent').map(function (raw) {
return new ical.Event(raw);
});
var events = [];
var ev, p = function (p) {return ev.component.getFirstPropertyValue(p);};
for (var i in rawEvents) {
ev = rawEvents[i];
if (ev.isRecurring()) {
var iter = ev.iterator();
var duration = p('dtend').toUnixTime()-p('dtstart').toUnixTime();
for (var i = 0; i < 100; i++) {
var next = iter.next();
if (next === undefined) {break;}
var start = next.toUnixTime()+TZOFFSET;
events.push({
title: p('summary'),
start: start,
end: start + duration
});
}
} else {
events.push({
title: p('summary'),
start: p('dtstart').toUnixTime()+TZOFFSET,
end: p('dtend').toUnixTime()+TZOFFSET,
});
}
}
events.sort(function (a, b) {
return a.start - b.start;
});
var threshold = Date.now()/1000 - 5*60*60; //show 5 hours ago
var i;
for (i in events) {
if (events[i].end > threshold) {
i = parseInt(i);
break;
}
}
var now = new Date();
cb(events.slice(i, i+count).map(function (ev) {
var start = new Date(ev.start*1000);
if (start.getMonth() == now.getMonth() && start.getDate() == now.getDate()) {
ev.startRendered = pad(start.getHours(),2)+':'+pad(start.getMinutes(),2);
} else {
ev.startRendered = DOW[start.getDay()]+', '+pad(start.getDate(),2)
+'.'+pad(start.getMonth()+1,2)+'. '+pad(start.getHours(),2)
+':'+pad(start.getMinutes(),2);
}
var end = new Date(ev.end*1000);
if (ev.end - ev.start >= 60*60*24) {
ev.endRendered = DOW[end.getDay()]+' '+pad(end.getHours(),2)
+':'+pad(end.getMinutes(),2);
} else {
ev.endRendered = pad(end.getHours(),2)+':'+pad(end.getMinutes(),2);
}
var dur = Math.floor((ev.end-ev.start)/60);
ev.duration = pad(Math.floor(dur/60),2)+':'+pad((dur%60),2)
if (start.getTime() < now.getTime()) {
if (end.getTime() < now.getTime()) {
ev.past = true;
} else {
ev.now = true;
}
}
return ev
}));
});
}
module.exports = function (io) {
function update(firstRunCallback) {
getData(8, function (data) {
CALENDAR = data;
io.emit('calendar', Mustache.render(TEMPLATE, CALENDAR));
if (firstRunCallback) {
firstRunCallback()
firstRunCallback = null;
}
});
}
update(function () {
var pushToClients = function (sock) {
sock.emit('calendar', Mustache.render(TEMPLATE, CALENDAR));
};
io.on('connect', pushToClients);
pushToClients(io);
});
setInterval(update, 600000);
}
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
function date() {
var d = new Date();
return DOW[d.getDay()]+', '+
pad(d.getDate(),2)+'.'+pad(d.getMonth()+1,2)+'.'+d.getFullYear()+' '+
pad(d.getHours(),2)+':'+pad(d.getMinutes(),2)+':'+pad(d.getSeconds(),2);
}
module.exports = function (io) {
setInterval(function () {
io.emit('date', '<div align="right"><h2>'+date()+'&nbsp;</h2></div>');
}, 1000);
}
var Mustache = require('mustache');
var httpreq = require('httpreq');
var TEMPLATES = {main: ''};
require('fs').readFile('modules/diagrams/main.mustache', 'utf-8', function (err, data) {
TEMPLATES.main = data;
});
require('fs').readFile('modules/diagrams/data.mustache', 'utf-8', function (err, data) {
TEMPLATES.data = data;
});
function fetchData(id, cb) {
var url = "http://shiny.tinyhost.de/php/getdata.php?time=1&id[]="+id;
httpreq.get(url, {binary: true}, function (err, res) {
try {
cb(res.body.toString().split('\n'));
} catch(e) {}
});
}
DATA = {power: '[]', devices: '[]'};
function handleData(prop, data) {
var line,out = []
for (var i = 1; i < data.length-1; i++) {
line = data[i].split(',');
if (line.length === 2) {
out.push([ (new Date(line[0])).getTime() , parseFloat(line[1]) ])
}
}
DATA[prop] = JSON.stringify(out);
}
function update(cb) {
var counter = 0;
var next = function () {
if (++counter === 2) {
cb();
}
}
fetchData(1, function (data) {
handleData('power', data);
next();
}); //power
fetchData(4, function (data) {
handleData('devices', data);
next();
}); //devices
}
module.exports = function (io) {
setInterval(function () {
update(function () {
io.emit('diagrams.data', Mustache.render(TEMPLATES.data, DATA));
});
}, 5000);
io.on('connect', function (sock) {
sock.emit('diagrams', Mustache.render(TEMPLATES.main, {}));
});
}
var irc = require('irc');
var CHANNEL = '#stratum0';
var PW = 'Fagee9ie'
module.exports = function (io) {
var client = new irc.Client('bouncer.ksal.de', 'infodisplay', {
channels: [CHANNEL],
port: 28921,
secure: true,
selfSigned: true,
userName: 'infodisplay/Freenode',
password: PW
});
var content = [];
client.addListener('message', function (from, to, message) {
if (to != CHANNEL || from === undefined) {return;}
message = message.replace(/</g,'&lt;').replace(/>/g,'&gt;');
content.push('<p><span>'+from+'</span> '+message+'</p>');
if (content.length > 25) {
content.shift();
}
io.emit('irc.inner', content.join(''));
});
io.on('connect', function (sock) {
sock.emit('irc', '<h3>&nbsp;IRC #stratum0</h3><div class="chat" data-infodisplay-outlet="inner"></div>');
setTimeout(function () {
sock.emit('irc.inner', content.join(''));
}, 3000);
});
}
var httpreq = require('httpreq');
var fs = require('fs');
var Mustache = require('mustache');
///CONFIG
var APPID = "fdc3690e6f9a7572128fe4012b4a2500"
var CITYID = "2945024"
/// STATICS
var directions = {NNE:11.25,NE:33.75,ENE:56.25,E:78.75,ESE:101.25,SE:123.75,SSE:146.25,S:168.75,SSW:191.25,SW:213.75,WSW:236.25,W:258.75,WNW:281.25,NW:303.75,NNW:326.25,N:348.75}
var iconBaseURL = 'http://openweathermap.org/img/w/';
var TEMPLATE = '';
fs.readFile('modules/weather/template.mustache', 'utf-8', function (err, data) {
TEMPLATE = data;
});
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
function fetchCurrent (cityid, cb) {
var url = "http://api.openweathermap.org/data/2.5/weather?units=metric&id="+cityid+"&appid="+APPID;
httpreq.get(url, function (err, res) {
var dat = JSON.parse(res.body);
if (dat.cod) {
cb({
temp: dat.main.temp,
wind: {speed: dat.wind.speed, dir: degToDirection(dat.wind.deg)},
pressure: dat.main.pressure,
humidity: dat.main.humidity,
main: dat.weather[0].main,
desc: dat.weather[0].description,
icon: iconBaseURL+dat.weather[0].icon+'.png'
});
}
});
}
function fetchForecast (cityid, count, cb) {
var url = "http://api.openweathermap.org/data/2.5/forecast?units=metric&id="+cityid+"&appid="+APPID;
httpreq.get(url, function (err, res) {
var raw = JSON.parse(res.body);
if (raw.list) {
var dat = raw.list.slice(0,count);
cb(dat.map(function (d) {
var date = new Date(d.dt*1000);
return {
time: pad(date.getHours(),2)+':'+pad(date.getMinutes(),2),
temp: d.main.temp,
wind: {speed: d.wind.speed, dir: degToDirection(d.wind.deg)},
main: d.weather[0].main,
desc: d.weather[0].description,
icon: iconBaseURL+d.weather[0].icon+'.png'
}
}));
}
});
}
function degToDirection(deg) {
var dir = 'N';
for (i in directions) {
if (deg > directions[i]) {
dir = i;
}
}
return dir;
}
module.exports = function (io) {
var context = {};
var firstTime = true;
var update = function (firstUpdateCb) {
var then = function () {
if (context.current && context.forecast && firstTime) {
firstUpdateCb();
firstTime = false;
}
};
fetchCurrent(CITYID, function (current) {
context.current = current;
then();
});
fetchForecast(CITYID, 6, function (forecast) {
context.forecast = forecast;
then();
});
};
update(function () {
var pushToClients = function (sock) {
sock.emit('weather', Mustache.render(TEMPLATE, context));
};
io.on('connect', pushToClients);
pushToClients(io);
});
setInterval(update, 10*60*1000);
}
......@@ -4,19 +4,32 @@
"description": "",
"main": "main.js",
"dependencies": {
"babel-polyfill": "^6.23.0",
"ee-first": "^1.1.1",
"express": "^4.13.3",
"httpreq": "^0.4.13",
"ical.js": "^1.1.2",
"irc": "^0.4.0",
"irc": "^0.5.2",
"ms": "^0.7.1",
"mustache": "^2.2.0",
"pixl-xml": "^1.0.4",
"socket.io": "^1.3.7",
"time": "^0.11.4"
},
"devDependencies": {},
"devDependencies": {
"babel": "^6.23.0",
"babel-cli": "^6.23.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-node6": "^11.0.0",
"eslint": "^3.15.0",
"eslint-config-marudor": "^4.1.2",
"nodemon": "^1.11.0"
},
"scripts": {
"build": "babel src --out-dir modules --copy-files --source-maps",
"dev": "nodemon --watch modules --exec 'node main.js'",
"watch": "npm run build -- --watch",
"start": "node main.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kasalehlia",
......
html {
margin: 0px;
height: 100vh;
margin: 0px;
height: 100vh;
}
body {
margin: 0px;
padding: 0px;
max-width: 100%;
border: none;
height: 100vh;
display: flex;
flex-direction: column;
margin: 0px;
padding: 0px;
max-width: 100%;
border: none;
height: 100vh;
}
body > div {
position: fixed;
#border: 1px solid;
overflow: hidden;
#border: 1px solid;
overflow: hidden;
}
body > div > div {
overflow: hidden;
}
#irc p {
margin: 0px;
line-height: 120%;
padding-left: 1em;
margin: 0px;
line-height: 120%;
padding-left: 1em;
}
h2 {
margin: 0px;
margin: 0px;
}
h3 {
margin: 0px;
margin: 0px;
}
#irc {
font-size: 120%;
font-size: 120%;
}
#irc .chat {
display: flex;
justify-content: flex-end;
flex-direction: column;
height: calc(100% - 46px);
font-family: monospace;
overflow: hidden;
display: flex;
justify-content: flex-end;
flex-direction: column;
height: calc(100% - 46px);
font-family: monospace;
overflow: hidden;
}
#irc p span {
color: #268bd2;
color: #268bd2;
}
#irc p span::before {
content: "<";
color: #839496;
content: "<";
color: #839496;
}
#irc p span:after {
content: ">";
color: #839496;
content: ">";
color: #839496;
}
#weather {
font-size: 120%;
font-size: 120%;
}
#weather div {
float: left;
float: left;
}
#weather tr {
border-bottom: 1px solid;
border-bottom: 1px solid;
}
#weather th {
text-align: left;
text-align: left;
}
#weather h3 img {
height: 1em;
float: right;
margin-right: 0.5em;
height: 1em;
float: right;
margin-right: 0.5em;
}
#calendar {
font-size: 120%;
font-size: 120%;
}
#date h2 {
color: #93a1a1;
color: #93a1a1;
}
#brand img {
margin: 10px;
margin: 10px;
}
#brand {
font-size: 120%;
font-size: 120%;
}
#brand h3 {
color: #839496;
margin-left: 10px;
color: #839496;
margin-left: 10px;
}
#brand .person {
font-style: italic;
font-style: italic;
}
#brand .open {
color: #859900;
color: #859900;
}
#brand .closed {
color: #dc322f;
color: #dc322f;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Stratum 0 Infodisplay</title>
<link rel="stylesheet" href="/css/solarized-dark.min.css">
<link rel="stylesheet" href="/css/infodisplay.css">
<script src="/socket.io/socket.io.js"></script>
<script src="/js/jquery-2.1.4.min.js"></script>
<script src="/js/jquery.flot.min.js"></script>
<script src="/js/jquery.flot.time.min.js"></script>
<script src="/js/infodisplay.js"></script>
</head>
<body>
<div id="brand" style="width:25%;height:50%"></div>
<div id="diagrams" style="width:50%;height:50%;left:25%"></div>
<div id="date" style="width:25%;height:5%;left:75%"></div>
<div id="calendar" style="width:25%;height:45%;left:75%;top:5%"></div>
<div id="irc" style="width:50%;height:calc(50% - 10px);top:50%"></div>
<div id="bus" style="width:25%;height:50%;left:50%;top:50%"></div>
<div id="weather" style="width:25%;height:50%;left:75%;top:50%"></div>
</body>
<head>
<title>Stratum 0 Infodisplay</title>
<link rel="stylesheet" href="/css/solarized-dark.min.css">
<link rel="stylesheet" href="/css/infodisplay.css">
<script src="/socket.io/socket.io.js"></script>
<script src="/js/jquery-2.1.4.min.js"></script>
<script src="/js/jquery.flot.min.js"></script>
<script src="/js/jquery.flot.time.min.js"></script>
<script src="/js/infodisplay.js"></script>
</head>
<body>
<div style="height:50%;display:flex;flex:1;">
<div class="component" id="brand" style="width:445px;"></div>
<div class="component" id="diagrams" style="flex:1;"></div>
<div style="display:flex;flex-direction:column;">
<div class="component" id="date"></div>
<div class="component" id="calendar"></div>
</div>
</div>
<div style="height:50%;display:flex;flex:1;">
<div class="component" id="irc" style="flex:1;"></div>
<div class="component" id="bus" style="width:385px;"></div>
<div class="component" id="weather"></div>
</div>
</body>
</html>
......@@ -25,7 +25,7 @@ $(function () {
});
setIntervals = [];
});
$('body > div').each(function () {
$('.component').each(function () {
var e = $(this);
var outlets = new Set();
socket.on(e.attr('id'), function (cnt) {
......
import fs from 'fs';
import httpreq from 'httpreq';
import Mustache from 'Mustache';
const URL = 'https://stratum0.org/status/status.json';
const TEMPLATES = {
template: fs.readFileSync('modules/brand/template.mustache', 'utf-8'),
status: fs.readFileSync('modules/brand/status.mustache', 'utf-8'),
};
let status = {};
function renderStatus(sock, everything) {
const sendInner = function() {
status.random = `${Math.random()}`;
sock.emit('brand.status', Mustache.render(TEMPLATES.status, status));
};
if (everything) {
sock.emit('brand', Mustache.render(TEMPLATES.template, {}));
setTimeout(sendInner, 3000);
} else {
sendInner();
}
}
function fetchStatus(cb) {
httpreq.get(URL, (err, res) => {
const state = JSON.parse(res.body).state;
cb(state);
});
}
module.exports = function(io) {
let firstTime = true;
function update() {
fetchStatus((state) => {
if (status.lastchange !== state.lastchange) {
const d = new Date(state.lastchange * 1000);
state.since = `${DOW[d.getDay()]}, ${pad(d.getHours(), 2)}:${
pad(d.getMinutes(), 2)}`;
status = state;
renderStatus(io);
}
if (firstTime && status) {
io.on('connection', (sock) => {
renderStatus(sock, true);
});
renderStatus(io, true);
firstTime = false;
} else {
renderStatus(io, false);
}
});
}
setInterval(update, 2 * 60 * 1000); //every 2 minutes
update();
};
File moved
File moved
/* eslint no-mixed-operators: 0 */
import fs from 'fs';
import httpreq from 'httpreq';
import Mustache from 'mustache';
import XML from 'pixl-xml';
/// CONFIG
const CITY = 'Braunschweig';
const STOPS = ['Ludwigstraße', 'Hamburger Straße'];
const ENTRIES = 6;
/// VARS
let CACHED = [];
const TEMPLATES = {
outer: fs.readFileSync('modules/bus/outer.mustache', 'utf-8'),
inner: fs.readFileSync('modules/bus/inner.mustache', 'utf-8'),
};
function fetchData(stop, cb) {
const url = `http://62.154.206.87/efaws2/default/XML_DM_REQUEST?sessionID=0&requestID=0&language=de&useRealtime=1&coordOutputFormat=WGS84[DD.ddddd]&locationServerActive=1&mode=direct&dmLineSelectionAll=1&depType=STOPEVENTS&useAllStops=1&command=null&type_dm=stop&name_dm=${ CITY } ${ stop }&mId=efa_rc2`;
httpreq.get(url, { binary: true }, (err, res) => {
try {
cb(XML.parse(res.body));
} catch (e) {
// Swallow
}
});
}
function renderLine(line) {
let image = '';
if (line.charAt(0) === 'M') {
image = 'metro.svg';
line = line.substr(1); // eslint-disable-line
} else if (line.length < 3) {
image = 'tram.svg';
} else {
image = 'bus.svg';
}
return `<img src="/modules/bus/${image}"> ${line}`;
}
function getData(stop, count, cb) {
fetchData(stop, (data) => {
const deps = data.itdDepartureMonitorRequest.itdDepartureList.itdDeparture;
cb(deps.slice(0, count).map((dep) => ({
line: dep.itdServingLine.symbol,
renderedLine: renderLine(dep.itdServingLine.symbol),
dir: dep.itdServingLine.direction.replace(CITY, '').trim(),
platform: dep.platform,
mean: dep.itdServingLine.itdNoTrain.name,
day: pad(dep.itdDateTime.itdDate.day, 2),
month: pad(dep.itdDateTime.itdDate.month, 2),
hour: pad(dep.itdDateTime.itdTime.hour, 2),
minute: pad(dep.itdDateTime.itdTime.minute, 2),
})));
});
}
function update(io, allStopsDoneCb) {
const done = [];
const context = [];
const innerGetData = function(stop, i) {
const ns = normalizeStop(stop);
getData(stop, ENTRIES, (deps) => {
try {
context[i] = { stop, normalizedStop: ns, deps };
io.emit(`bus.${ns}`, Mustache.render(TEMPLATES.inner, context[i]));
if (done.indexOf(stop) === -1) {
done.push(stop);
if (done.length === STOPS.length) {
allStopsDoneCb();
}
}
CACHED = context;
} catch (e) {
console.log(e); // eslint-disable-line
}
// calculate when to update next
const d = new Date();
const hour = d.getHours();
const minute = d.getMinutes();
const depHour = deps[0].hour < hour ? deps[0].hour + 24 : deps[0].hour;
const diff = (depHour - hour) * 60 + (deps[0].minute - minute);
setTimeout(() => {
innerGetData(stop, i);
}, (diff * 60 + (60 - d.getSeconds()) % 60) * 1000);
});
};
STOPS.forEach((stop, i) => {
innerGetData(stop, i);
});
}
function normalizeStop(stop) {
return stop.replace(/[^a-zA-Z0-9_]/g, '');
}
module.exports = function(io) {
update(io, () => {
const pushToClient = function(sock) {
sock.emit('bus', Mustache.render(TEMPLATES.outer, CACHED));
setTimeout(() => {
for (const i in CACHED) { // eslint-disable-line
sock.emit(`bus.${CACHED[i].normalizedStop}`,
Mustache.render(TEMPLATES.inner, CACHED[i]));
}
}, 3000); //wait a second to let the client process the outlets
};
io.on('connect', pushToClient);
pushToClient(io);
});
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment