Skip to content

Instantly share code, notes, and snippets.

@Sillium
Last active March 1, 2023 13:40
Show Gist options
  • Save Sillium/0ef7decee63fc57d52a564d9982c0525 to your computer and use it in GitHub Desktop.
Save Sillium/0ef7decee63fc57d52a564d9982c0525 to your computer and use it in GitHub Desktop.
Library to fetch data from Telekom API
console.log("Test");
class TelekomDataService {
/*---
/ STATIC PROPERTIES
/---*/
static fileManager = FileManager.iCloud();
static scriptDir = module.filename.replace(TelekomDataService.fileManager.fileName(module.filename, true), '');
static cacheFile = TelekomDataService.fileManager.joinPath(TelekomDataService.scriptDir, "cache.json");
static historyDir = TelekomDataService.fileManager.joinPath(TelekomDataService.scriptDir, "history");
/*---
/ STATIC METHODS
/---*/
static #formatVolume(amount, language) {
var formatterGiga = new Intl.NumberFormat(language, {
style: 'decimal',
minimumFractionDigits: 0,
maximumFractionDigits: 2
});
let amount_str;
if (amount >= 100*1024*1024) {
amount_str = formatterGiga.format(amount / (1024*1024*1024)) + " GB";
} else if (amount >= 100*1024) {
amount_str = formatterGiga.format(amount / (1024*1024)) + " MB";
} else if (amount >= 100) {
amount_str = formatterGiga.format(amount / 1024) + " kB";
} else {
amount_str = formatterGiga.format(amount) + " B";
}
return amount_str;
}
/**
* Translates seconds into human readable format of seconds, minutes, hours, days, and years
*
* @param {number} seconds The number of seconds to be processed
* @return {string} The phrase describing the amount of time
*/
static #forHumans(seconds) {
var levels = [
[Math.floor(seconds / 31536000), 'years'],
[Math.floor((seconds % 31536000) / 86400), 'days'],
[Math.floor(((seconds % 31536000) % 86400) / 3600), 'hours'],
[Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'minutes'],
[(((seconds % 31536000) % 86400) % 3600) % 60, 'seconds'],
];
var returntext = '';
for (var i = 0, max = levels.length; i < max; i++) {
if ( levels[i][0] === 0 ) continue;
returntext += ' ' + levels[i][0] + ' ' + (levels[i][0] === 1 ? levels[i][1].substr(0, levels[i][1].length-1): levels[i][1]);
};
return returntext.trim();
}
static #makeSureDirectoryExists(dir) {
if (TelekomDataService.fileManager.fileExists(dir) && !TelekomDataService.fileManager.isDirectory(dir)) {
TelekomDataService.fileManager.remove(dir);
}
if (!TelekomDataService.fileManager.fileExists(dir)) {
TelekomDataService.fileManager.createDirectory(dir, true);
}
}
static async #makeSureFileIsDownloadedFromiCloud(file) {
if (TelekomDataService.fileManager.fileExists(file)) {
await TelekomDataService.fileManager.downloadFileFromiCloud(file);
}
}
/*---
/ PRIVATE PROPERTIES
/---*/
#source = "UNINITIALIZED"
#rawData = {
additionalData: {}
};
#fetchedAt = null;
#fetchedByDevice = null;
/*---
/ PRIVATE METHODS
/---*/
async #writeToCache() {
await TelekomDataService.#makeSureFileIsDownloadedFromiCloud(TelekomDataService.cacheFile);
TelekomDataService.fileManager.writeString(TelekomDataService.cacheFile, JSON.stringify(this.rawData, null, 2));
}
async #writeToHistory() {
const dateFormatter = new DateFormatter();
dateFormatter.dateFormat = 'yyyy/MM/dd';
const dayDir = TelekomDataService.fileManager.joinPath(TelekomDataService.historyDir, dateFormatter.string(this.usedAtUTC));
TelekomDataService.#makeSureDirectoryExists(dayDir);
dateFormatter.dateFormat = 'HH-mm-ss';
const historyFile = TelekomDataService.fileManager.joinPath(dayDir, dateFormatter.string(this.usedAtUTC) + ".json");
await TelekomDataService.#makeSureFileIsDownloadedFromiCloud(historyFile);
TelekomDataService.fileManager.writeString(historyFile, JSON.stringify(this.rawData, null, 2));
const datestr = this.usedAtStr.split(" ")[0];
const year = datestr.split("-")[0];
const month = datestr.split("-")[1];
const day = datestr.split("-")[2];
const lastFileOfDay = TelekomDataService.fileManager.joinPath(TelekomDataService.historyDir, year + "-" + month + "-" + day + ".json");
await TelekomDataService.#makeSureFileIsDownloadedFromiCloud(lastFileOfDay);
TelekomDataService.fileManager.writeString(lastFileOfDay, JSON.stringify(this.rawData, null, 2));
const lastFileOfMonth = TelekomDataService.fileManager.joinPath(TelekomDataService.historyDir, year + "-" + month + ".json");
await TelekomDataService.#makeSureFileIsDownloadedFromiCloud(lastFileOfMonth);
TelekomDataService.fileManager.writeString(lastFileOfMonth, JSON.stringify(this.rawData, null, 2));
}
async #readCachedData() {
try {
const cacheData = JSON.parse(TelekomDataService.fileManager.readString(TelekomDataService.cacheFile), null);
//delete cacheData.additionalData;
console.log("Fetched cached data from cache file:\n" + JSON.stringify(cacheData, null, 2));
this.#source = "CACHE";
cacheData.additionalData.source = this.source;
this.#rawData = cacheData;
} catch(err) {
console.log("Error while reading cache file:\n" + err);
}
}
async #readProviderData() {
try {
const req = new Request("https://pass.telekom.de/api/service/generic/v1/status");
req.headers = {
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.1 Mobile/15E148 Safari/604.1"
}
const providerData = await req.loadJSON();
console.log("Request object:\n" + JSON.stringify(req, null, 2));
if (isEmpty(providerData)) {
throw "Returned data is empty.";
}
if ('error' in providerData) {
throw "Returned data contains error message: " + providerData.error;
}
console.log("Fetched fresh data from Telekom API:\n" + JSON.stringify(providerData, null, 2))
this.#source = "PROVIDER";
this.#fetchedAt = Date.now();
this.#fetchedByDevice = Device.name();
let additionalData = {
//source: this.source,
fetchedByDevice: this.fetchedByDevice,
availableVolume: this.availableVolume,
availableVolumeForHumans: this.availableVolumeForHumans,
usedVolumeForHumans: this.usedVolumeForHumans,
initialVolumeForHumans: this.initialVolumeForHumans,
remainingDays: this.remainingDays,
remainingTimeForHumans: this.remainingTimeForHumans,
availablePercentage: this.availablePercentage,
fetchedAtUTC: this.fetchedAtUTC,
fetchedAtUTCMs: this.fetchedAtUTCMs,
fetchedAtStr: this.fetchedAtStr,
usedAtUTC: this.usedAtUTC,
usedAtUTCMs: this.usedAtUTCMs,
usedAtStr: this.usedAtStr
}
this.#rawData = {
...providerData,
additionalData
}
this.#writeToCache();
// if (this.#enableWriteToHistory) {
this.#writeToHistory();
// }
} catch(err) {
console.log("Error while accessing Telekom API:\n" + err);
}
}
/*---
/ CONSTRUCTOR
/---*/
/*
constructor(enableWriteToHistory = true) {
this.#enableWriteToHistory = enableWriteToHistory;
console.log("TelekomDataService (" + module.filename + ") object instantiated.");
}
*/
constructor() {
console.log("TelekomDataService (" + module.filename + ") object instantiated.");
}
/*---
/ PUBLIC METHODS
/---*/
async update() {
await this.#readCachedData();
await this.#readProviderData();
}
get rawData() {
return this.#rawData;
}
get data() {
let data = {
...this.rawData
}
data.additionalData.source = this.source;
return data;
}
get source() {
return this.#source;
}
get usedAt() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.usedAt;
}
get initialVolume() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.initialVolume;
}
get initialVolumeStr() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.initialVolumeStr;
}
get usedVolume() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.usedVolume;
}
get usedVolumeStr() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.usedVolumeStr;
}
get usedPercentage() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.usedPercentage;
}
get remainingSeconds() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.remainingSeconds;
}
get remainingTimeStr() {
if (isEmpty(this.rawData)) {
return null;
}
return this.rawData.remainingTimeStr;
}
get availableVolume() {
if (isEmpty(this.rawData)) {
return null;
}
return this.initialVolume - this.usedVolume;
}
get availableVolumeForHumans() {
if (isEmpty(this.rawData)) {
return null;
}
return TelekomDataService.#formatVolume(this.availableVolume, 'en');
}
get initialVolumeForHumans() {
if (isEmpty(this.rawData)) {
return null;
}
return TelekomDataService.#formatVolume(this.initialVolume, 'en');
}
get usedVolumeForHumans() {
if (isEmpty(this.rawData)) {
return null;
}
return TelekomDataService.#formatVolume(this.usedVolume, 'en');
}
get remainingDays() {
if (isEmpty(this.rawData)) {
return null;
}
return Math.floor(this.remainingSeconds / (24 * 60 * 60));
}
get remainingTimeForHumans() {
if (isEmpty(this.rawData)) {
return null;
}
return TelekomDataService.#forHumans(this.remainingSeconds);
}
get availablePercentage() {
if (isEmpty(this.rawData)) {
return null;
}
return 100 - this.usedPercentage;
}
get fetchedByDevice() {
return this.#fetchedByDevice;
}
get fetchedAt() {
return this.#fetchedAt;
}
get fetchedAtUTC() {
if (!!this.fetchedAt) {
var fetchedAt = new Date();
fetchedAt.setTime(this.fetchedAt);
return fetchedAt;
}
return null;
}
get fetchedAtUTCMs() {
if (!!this.fetchedAtUTC) {
return this.fetchedAtUTC.getTime();
}
return null;
}
get fetchedAtStr() {
if (!!this.fetchedAtUTC) {
let dF = new DateFormatter();
dF.dateFormat = 'yyyy-MM-dd HH-mm-ss';
return dF.string(this.fetchedAtUTC);
}
return null;
}
get usedAtUTC() {
if (isEmpty(this.rawData)) {
return null;
}
var usedAt = new Date();
usedAt.setTime(this.rawData.usedAt);
return usedAt;
}
get usedAtUTCMs() {
if (isEmpty(this.rawData)) {
return null;
}
return this.usedAtUTC.getTime();
}
get usedAtStr() {
if (isEmpty(this.rawData)) {
return null;
}
let dF = new DateFormatter();
dF.dateFormat = 'yyyy-MM-dd HH-mm-ss';
return dF.string(this.usedAtUTC);
}
}
module.exports = TelekomDataService;
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment