2016-04-15 12:18:59 +02:00
|
|
|
/* Magic Mirror
|
|
|
|
* Node Helper: Calendar - CalendarFetcher
|
|
|
|
*
|
2020-04-28 23:05:28 +02:00
|
|
|
* By Michael Teeuw https://michaelteeuw.nl
|
2016-04-15 12:18:59 +02:00
|
|
|
* MIT Licensed.
|
|
|
|
*/
|
2020-12-23 12:45:03 +01:00
|
|
|
const CalendarUtils = require("./calendarutils");
|
2021-02-18 19:14:53 +01:00
|
|
|
const Log = require("logger");
|
2020-09-22 07:25:48 -05:00
|
|
|
const ical = require("node-ical");
|
2021-03-05 00:13:32 +01:00
|
|
|
const fetch = require("node-fetch");
|
|
|
|
const digest = require("digest-fetch");
|
2021-03-02 21:26:25 +01:00
|
|
|
const https = require("https");
|
2016-04-15 12:18:59 +02:00
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {string} url The url of the calendar to fetch
|
|
|
|
* @param {number} reloadInterval Time in ms the calendar is fetched again
|
|
|
|
* @param {string[]} excludedEvents An array of words / phrases from event titles that will be excluded from being shown.
|
|
|
|
* @param {number} maximumEntries The maximum number of events fetched.
|
|
|
|
* @param {number} maximumNumberOfDays The maximum number of days an event should be in the future.
|
|
|
|
* @param {object} auth The object containing options for authentication against the calendar.
|
|
|
|
* @param {boolean} includePastEvents If true events from the past maximumNumberOfDays will be fetched too
|
2021-02-21 10:29:40 +01:00
|
|
|
* @param {boolean} selfSignedCert If true, the server certificate is not verified against the list of supplied CAs.
|
2020-08-03 11:19:54 +02:00
|
|
|
* @class
|
|
|
|
*/
|
2021-02-21 10:29:40 +01:00
|
|
|
const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, includePastEvents, selfSignedCert) {
|
2020-06-18 21:54:51 +02:00
|
|
|
let reloadTimer = null;
|
|
|
|
let events = [];
|
2016-04-15 12:18:59 +02:00
|
|
|
|
2020-06-17 21:37:49 +02:00
|
|
|
let fetchFailedCallback = function () {};
|
|
|
|
let eventsReceivedCallback = function () {};
|
2016-04-15 12:18:59 +02:00
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Initiates calendar fetch.
|
|
|
|
*/
|
2020-12-31 21:51:20 +01:00
|
|
|
const fetchCalendar = () => {
|
2021-03-06 21:19:14 +01:00
|
|
|
clearTimeout(reloadTimer);
|
|
|
|
reloadTimer = null;
|
|
|
|
const nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
|
|
|
|
let fetcher = null;
|
|
|
|
let httpsAgent = null;
|
|
|
|
let headers = {
|
|
|
|
"User-Agent": "Mozilla/5.0 (Node.js " + nodeVersion + ") MagicMirror/" + global.version + " (https://github.com/MichMich/MagicMirror/)"
|
|
|
|
};
|
2016-09-08 17:36:30 +02:00
|
|
|
|
2021-03-06 21:19:14 +01:00
|
|
|
if (selfSignedCert) {
|
|
|
|
httpsAgent = new https.Agent({
|
|
|
|
rejectUnauthorized: false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (auth) {
|
|
|
|
if (auth.method === "bearer") {
|
|
|
|
headers.Authorization = "Bearer " + auth.pass;
|
|
|
|
} else if (auth.method === "digest") {
|
2021-04-15 14:51:33 +02:00
|
|
|
fetcher = new digest(auth.user, auth.pass).fetch(url, { headers: headers, agent: httpsAgent });
|
2021-03-06 21:19:14 +01:00
|
|
|
} else {
|
2021-03-14 19:38:03 +01:00
|
|
|
headers.Authorization = "Basic " + Buffer.from(auth.user + ":" + auth.pass).toString("base64");
|
2021-03-05 00:13:32 +01:00
|
|
|
}
|
2016-06-04 20:32:55 -06:00
|
|
|
}
|
2021-03-06 21:19:14 +01:00
|
|
|
if (fetcher === null) {
|
2021-04-15 14:51:33 +02:00
|
|
|
fetcher = fetch(url, { headers: headers, agent: httpsAgent });
|
2021-03-06 21:19:14 +01:00
|
|
|
}
|
2016-09-08 17:36:30 +02:00
|
|
|
|
2021-03-06 21:19:14 +01:00
|
|
|
fetcher
|
2021-03-02 21:26:25 +01:00
|
|
|
.catch((error) => {
|
2021-03-14 10:01:52 +01:00
|
|
|
fetchFailedCallback(this, error);
|
2020-11-24 21:32:16 +01:00
|
|
|
scheduleTimer();
|
2021-03-02 21:26:25 +01:00
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
if (response.status !== 200) {
|
2021-03-14 10:01:52 +01:00
|
|
|
fetchFailedCallback(this, response.statusText);
|
2021-03-04 21:12:53 +01:00
|
|
|
scheduleTimer();
|
2021-03-02 21:26:25 +01:00
|
|
|
}
|
|
|
|
return response;
|
|
|
|
})
|
|
|
|
.then((response) => response.text())
|
|
|
|
.then((responseData) => {
|
|
|
|
let data = [];
|
|
|
|
|
|
|
|
try {
|
|
|
|
data = ical.parseICS(responseData);
|
2020-12-25 12:59:08 +01:00
|
|
|
Log.debug("parsed data=" + JSON.stringify(data));
|
2020-12-26 12:12:44 +01:00
|
|
|
events = CalendarUtils.filterEvents(data, {
|
|
|
|
excludedEvents,
|
|
|
|
includePastEvents,
|
|
|
|
maximumEntries,
|
|
|
|
maximumNumberOfDays
|
|
|
|
});
|
2021-03-02 21:26:25 +01:00
|
|
|
} catch (error) {
|
2021-03-28 10:48:12 +02:00
|
|
|
fetchFailedCallback(this, error.message);
|
2021-03-02 21:26:25 +01:00
|
|
|
scheduleTimer();
|
2020-12-25 12:59:08 +01:00
|
|
|
return;
|
2020-06-20 09:01:35 +02:00
|
|
|
}
|
2020-12-31 21:51:20 +01:00
|
|
|
this.broadcastEvents();
|
2020-12-25 12:59:08 +01:00
|
|
|
scheduleTimer();
|
|
|
|
});
|
|
|
|
};
|
2018-03-18 23:33:48 -04:00
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Schedule the timer for the next update.
|
|
|
|
*/
|
2020-06-17 21:37:49 +02:00
|
|
|
const scheduleTimer = function () {
|
2016-04-15 12:18:59 +02:00
|
|
|
clearTimeout(reloadTimer);
|
2020-05-11 22:22:32 +02:00
|
|
|
reloadTimer = setTimeout(function () {
|
2016-04-15 12:18:59 +02:00
|
|
|
fetchCalendar();
|
|
|
|
}, reloadInterval);
|
|
|
|
};
|
|
|
|
|
|
|
|
/* public methods */
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Initiate fetchCalendar();
|
|
|
|
*/
|
2020-05-11 22:22:32 +02:00
|
|
|
this.startFetch = function () {
|
2016-04-15 12:18:59 +02:00
|
|
|
fetchCalendar();
|
|
|
|
};
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-06-04 20:32:55 -06:00
|
|
|
* Broadcast the existing events.
|
2016-04-15 12:18:59 +02:00
|
|
|
*/
|
2020-05-25 18:57:15 +02:00
|
|
|
this.broadcastEvents = function () {
|
2020-06-01 16:40:20 +02:00
|
|
|
Log.info("Calendar-Fetcher: Broadcasting " + events.length + " events.");
|
2020-12-31 21:51:20 +01:00
|
|
|
eventsReceivedCallback(this);
|
2016-04-15 12:18:59 +02:00
|
|
|
};
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Sets the on success callback
|
|
|
|
*
|
2020-08-03 11:19:54 +02:00
|
|
|
* @param {Function} callback The on success callback.
|
2016-04-15 12:18:59 +02:00
|
|
|
*/
|
2020-05-11 22:22:32 +02:00
|
|
|
this.onReceive = function (callback) {
|
2016-04-15 12:18:59 +02:00
|
|
|
eventsReceivedCallback = callback;
|
|
|
|
};
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Sets the on error callback
|
|
|
|
*
|
2020-08-03 11:19:54 +02:00
|
|
|
* @param {Function} callback The on error callback.
|
2016-04-15 12:18:59 +02:00
|
|
|
*/
|
2020-05-11 22:22:32 +02:00
|
|
|
this.onError = function (callback) {
|
2016-04-15 12:18:59 +02:00
|
|
|
fetchFailedCallback = callback;
|
|
|
|
};
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Returns the url of this fetcher.
|
|
|
|
*
|
2020-08-03 11:19:54 +02:00
|
|
|
* @returns {string} The url of this fetcher.
|
2016-04-15 12:18:59 +02:00
|
|
|
*/
|
2020-05-11 22:22:32 +02:00
|
|
|
this.url = function () {
|
2016-04-15 12:18:59 +02:00
|
|
|
return url;
|
|
|
|
};
|
|
|
|
|
2020-08-03 11:19:54 +02:00
|
|
|
/**
|
2016-04-15 12:18:59 +02:00
|
|
|
* Returns current available events for this fetcher.
|
|
|
|
*
|
2020-08-03 11:19:54 +02:00
|
|
|
* @returns {object[]} The current available events for this fetcher.
|
2016-04-15 12:18:59 +02:00
|
|
|
*/
|
2020-05-11 22:22:32 +02:00
|
|
|
this.events = function () {
|
2016-04-15 12:18:59 +02:00
|
|
|
return events;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2016-09-08 17:36:30 +02:00
|
|
|
module.exports = CalendarFetcher;
|